aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Puccinelli2010-08-11 01:11:16 +0000
committerTony Puccinelli2010-08-11 01:11:16 +0000
commit3a7a0ba720f219c4780cf19d196cda9c0456a20b (patch)
treefe7f45242447dc7d14447babbdea9fbbb771c506
parent6543062e5701e8011a4b12abffa8afca56f30b3f (diff)
parentfffec23a02cc88ed8daba0a3b50007b7e220c075 (diff)
downloadscummvm-rg350-3a7a0ba720f219c4780cf19d196cda9c0456a20b.tar.gz
scummvm-rg350-3a7a0ba720f219c4780cf19d196cda9c0456a20b.tar.bz2
scummvm-rg350-3a7a0ba720f219c4780cf19d196cda9c0456a20b.zip
manually merged engines from trunk into branch
svn-id: r51964
-rw-r--r--engines/drascula/animation.cpp2
-rw-r--r--engines/drascula/drascula.cpp1
-rw-r--r--engines/drascula/objects.cpp3
-rw-r--r--engines/m4/compression.h4
-rw-r--r--engines/m4/console.cpp56
-rw-r--r--engines/m4/console.h3
-rw-r--r--engines/m4/converse.cpp8
-rw-r--r--engines/m4/dialogs.cpp26
-rw-r--r--engines/m4/globals.h1
-rw-r--r--engines/m4/gui.cpp30
-rw-r--r--engines/m4/m4.cpp12
-rw-r--r--engines/m4/m4.h3
-rw-r--r--engines/m4/m4_views.cpp2
-rw-r--r--engines/m4/mads_anim.cpp16
-rw-r--r--engines/m4/mads_menus.cpp56
-rw-r--r--engines/mohawk/video/cinepak.cpp286
-rw-r--r--engines/mohawk/video/cinepak.h81
-rw-r--r--engines/mohawk/video/qdm2.cpp3063
-rw-r--r--engines/mohawk/video/qdm2.h289
-rw-r--r--engines/mohawk/video/qdm2data.h531
-rw-r--r--engines/mohawk/video/qt_player.cpp1272
-rw-r--r--engines/mohawk/video/qt_player.h282
-rw-r--r--engines/mohawk/video/qtrle.cpp420
-rw-r--r--engines/mohawk/video/qtrle.h58
-rw-r--r--engines/mohawk/video/rpza.cpp208
-rw-r--r--engines/mohawk/video/rpza.h49
-rw-r--r--engines/mohawk/video/smc.cpp385
-rw-r--r--engines/mohawk/video/smc.h59
-rw-r--r--engines/mohawk/video/video.cpp377
-rw-r--r--engines/mohawk/video/video.h107
-rw-r--r--engines/parallaction/debug.cpp27
-rw-r--r--engines/parallaction/debug.h1
-rw-r--r--engines/parallaction/dialogue.cpp4
-rw-r--r--engines/parallaction/exec_br.cpp2
-rw-r--r--engines/parallaction/graphics.cpp6
-rw-r--r--engines/parallaction/input.cpp15
-rw-r--r--engines/parallaction/objects.h4
-rw-r--r--engines/parallaction/parallaction.cpp112
-rw-r--r--engines/parallaction/parallaction.h2
-rw-r--r--engines/parallaction/parallaction_br.cpp4
-rw-r--r--engines/parallaction/parser.cpp9
-rw-r--r--engines/parallaction/parser_ns.cpp2
-rw-r--r--engines/parallaction/sound_br.cpp4
-rw-r--r--engines/saga/saga.cpp14
-rw-r--r--engines/sci/engine/script.cpp2
-rw-r--r--engines/sci/engine/script_patches.cpp93
-rw-r--r--engines/sci/engine/workarounds.cpp5
-rw-r--r--engines/sci/graphics/animate.cpp26
-rw-r--r--engines/sci/graphics/animate.h1
-rw-r--r--engines/sci/graphics/view.cpp2
-rw-r--r--engines/sci/sound/iterator/core.cpp1013
-rw-r--r--engines/sci/sound/iterator/core.h209
-rw-r--r--engines/sci/sound/iterator/iterator.cpp1686
-rw-r--r--engines/sci/sound/iterator/iterator.h326
-rw-r--r--engines/sci/sound/iterator/iterator_internal.h276
-rw-r--r--engines/sci/sound/iterator/songlib.cpp189
-rw-r--r--engines/sci/sound/iterator/songlib.h171
-rw-r--r--engines/sci/sound/iterator/test-iterator.cpp423
-rw-r--r--engines/scumm/charset.cpp2
-rw-r--r--engines/scumm/debugger.cpp2
-rw-r--r--engines/scumm/dialogs.cpp213
-rw-r--r--engines/scumm/dialogs.h24
-rw-r--r--engines/scumm/he/resource_he.cpp4
-rw-r--r--engines/scumm/input.cpp2
-rw-r--r--engines/scumm/scumm.cpp18
-rw-r--r--engines/scumm/scumm.h2
-rw-r--r--engines/sword1/animation.cpp38
-rw-r--r--engines/sword1/animation.h1
-rw-r--r--engines/sword2/animation.cpp37
-rw-r--r--engines/sword2/animation.h1
-rw-r--r--engines/tinsel/handle.cpp3
71 files changed, 458 insertions, 12207 deletions
diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp
index 1d6f77b8eb..d6a3bafd9f 100644
--- a/engines/drascula/animation.cpp
+++ b/engines/drascula/animation.cpp
@@ -1695,7 +1695,7 @@ void DrasculaEngine::animation_9_6() {
// We set the room number to -1 for the same purpose.
// Also check animation_2_1(), where the same hack was used
// by the original
- roomNumber = -1;
+ roomNumber = -2;
loadPic("nota2.alg", bgSurface, HALF_PAL);
black();
trackProtagonist = 1;
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index b1f16fa505..7e9f68a355 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -88,6 +88,7 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam
_textverbs = 0;
_textmisc = 0;
_textd1 = 0;
+ _talkSequences = 0;
_color = 0;
blinking = 0;
diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp
index 08c1a68a55..73aea7b7f2 100644
--- a/engines/drascula/objects.cpp
+++ b/engines/drascula/objects.cpp
@@ -92,7 +92,8 @@ void DrasculaEngine::gotoObject(int pointX, int pointY) {
updateRoom();
updateScreen();
- if (cursorVisible)
+ // roomNumber -2 is end credits. Do not show cursor there
+ if (cursorVisible && roomNumber != -2)
showCursor();
}
diff --git a/engines/m4/compression.h b/engines/m4/compression.h
index 74fed357ff..00e3d1f927 100644
--- a/engines/m4/compression.h
+++ b/engines/m4/compression.h
@@ -66,8 +66,8 @@ public:
class FabDecompressor {
private:
- int _bitsLeft;
- uint32 _bitBuffer;
+ int _bitsLeft;
+ uint32 _bitBuffer;
const byte *_srcData, *_srcP;
int _srcSize;
diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp
index 9a92cb04d1..71c70e3e1b 100644
--- a/engines/m4/console.cpp
+++ b/engines/m4/console.cpp
@@ -47,7 +47,6 @@ Console::Console(MadsM4Engine *vm) : GUI::Debugger() {
DCmd_Register("start_conv", WRAP_METHOD(Console, cmdStartConversation));
DCmd_Register("textview", WRAP_METHOD(Console, cmdShowTextview));
DCmd_Register("animview", WRAP_METHOD(Console, cmdShowAnimview));
- DCmd_Register("anim", WRAP_METHOD(Console, cmdPlayAnimation));
}
Console::~Console() {
@@ -247,33 +246,6 @@ bool Console::cmdShowAnimview(int argc, const char **argv) {
return false;
}
-bool Console::cmdPlayAnimation(int argc, const char **argv) {
- View *view = _vm->_viewManager->getView(VIEWID_SCENE);
- if (view == NULL) {
- DebugPrintf("The scene view isn't currently active\n");
- } else if (argc != 2 && argc != 3) {
- DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
- DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
- } else {
- char resourceName[20];
- strncpy(resourceName, argv[1], 15);
- resourceName[15] = '\0';
- if (!strchr(resourceName, '.'))
- strcat(resourceName, ".AA");
-
- _vm->_viewManager->moveToFront(view);
- if (argc == 3 && atoi(argv[2]) == 1)
- _vm->_animation->loadFullScreen(resourceName);
- else
- _vm->_animation->load(resourceName);
- _vm->_animation->start();
- view->restore(0, 0, view->width(), view->height());
- return false;
- }
-
- return true;
-}
-
/*--------------------------------------------------------------------------*/
MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
@@ -282,6 +254,7 @@ MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
DCmd_Register("object", WRAP_METHOD(MadsConsole, cmdObject));
DCmd_Register("message", WRAP_METHOD(MadsConsole, cmdMessage));
DCmd_Register("scene_info", WRAP_METHOD(MadsConsole, cmdSceneInfo));
+ DCmd_Register("anim", WRAP_METHOD(MadsConsole, cmdPlayAnimation));
}
bool MadsConsole::cmdObject(int argc, const char **argv) {
@@ -386,6 +359,33 @@ bool MadsConsole::cmdSceneInfo(int argc, const char **argv) {
return true;
}
+bool MadsConsole::cmdPlayAnimation(int argc, const char **argv) {
+ View *view = _vm->_viewManager->getView(VIEWID_SCENE);
+ if (view == NULL) {
+ DebugPrintf("The scene view isn't currently active\n");
+ } else if (argc != 2 && argc != 3) {
+ DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
+ DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
+ } else {
+ char resourceName[20];
+ strncpy(resourceName, argv[1], 15);
+ resourceName[15] = '\0';
+ if (!strchr(resourceName, '.'))
+ strcat(resourceName, ".AA");
+
+ _vm->_viewManager->moveToFront(view);
+ if (argc == 3 && atoi(argv[2]) == 1)
+ _madsVm->_palette->deleteAllRanges();
+
+ _madsVm->scene()->_sceneAnimation->load(resourceName, 0);
+
+ view->restore(0, 0, view->width(), view->height());
+ return false;
+ }
+
+ return true;
+}
+
/*--------------------------------------------------------------------------*/
M4Console::M4Console(M4Engine *vm): Console(vm) {
diff --git a/engines/m4/console.h b/engines/m4/console.h
index b592f041cf..53a47dada9 100644
--- a/engines/m4/console.h
+++ b/engines/m4/console.h
@@ -50,7 +50,6 @@ private:
bool cmdStartConversation(int argc, const char **argv);
bool cmdShowTextview(int argc, const char **argv);
bool cmdShowAnimview(int argc, const char **argv);
- bool cmdPlayAnimation(int argc, const char **argv);
public:
Console(MadsM4Engine *vm);
@@ -64,6 +63,8 @@ private:
bool cmdObject(int argc, const char **argv);
bool cmdMessage(int argc, const char **argv);
bool cmdSceneInfo(int argc, const char **argv);
+ bool cmdPlayAnimation(int argc, const char **argv);
+
public:
MadsConsole(MadsEngine *vm);
virtual ~MadsConsole() {}
diff --git a/engines/m4/converse.cpp b/engines/m4/converse.cpp
index aab2fc95ce..af26a86313 100644
--- a/engines/m4/converse.cpp
+++ b/engines/m4/converse.cpp
@@ -96,7 +96,7 @@ void ConversationView::setNode(int32 nodeIndex) {
_vm->_font->setFont(FONT_CONVERSATION);
// TODO: Conversation styles and colors
- _vm->_font->setColors(2, 1, 3);
+ _vm->_font->current()->setColours(2, 1, 3);
_currentNodeIndex = nodeIndex;
@@ -124,7 +124,7 @@ void ConversationView::setNode(int32 nodeIndex) {
}
// Figure out the longest string to determine where option highlighting ends
- int tempX = _vm->_font->getWidth(node->entries[i]->text, 0) +
+ int tempX = _vm->_font->current()->getWidth(node->entries[i]->text, 0) +
CONV_ENTRIES_X_OFFSET + 10;
_xEnd = MAX(_xEnd, tempX);
}
@@ -163,10 +163,10 @@ void ConversationView::onRefresh(RectList *rects, M4Surface *destSurface) {
if (i > CONV_MAX_SHOWN_ENTRIES - 1)
break;
- _vm->_font->setColor((_highlightedIndex == i) ? CONVERSATION_ENTRY_HIGHLIGHTED :
+ _vm->_font->current()->setColour((_highlightedIndex == i) ? CONVERSATION_ENTRY_HIGHLIGHTED :
CONVERSATION_ENTRY_NORMAL);
- _vm->_font->writeString(this, _activeItems[i]->text, CONV_ENTRIES_X_OFFSET,
+ _vm->_font->current()->writeString(this, _activeItems[i]->text, CONV_ENTRIES_X_OFFSET,
CONV_ENTRIES_Y_OFFSET + CONV_ENTRIES_HEIGHT * i, 0, 0);
}
}
diff --git a/engines/m4/dialogs.cpp b/engines/m4/dialogs.cpp
index 3af94af262..a7104537f5 100644
--- a/engines/m4/dialogs.cpp
+++ b/engines/m4/dialogs.cpp
@@ -127,7 +127,7 @@ void Dialog::writeChars(const char *srcLine) {
strcat(line, wordStr);
lineLen = strlen(line);
- lineWidth = _vm->_font->getWidth(line, DIALOG_SPACING);
+ lineWidth = _vm->_font->current()->getWidth(line, DIALOG_SPACING);
if (((_lineX + lineLen) > _widthChars) || ((_widthX + lineWidth) > _dialogWidth)) {
incLine();
@@ -146,7 +146,7 @@ void Dialog::writeChars(const char *srcLine) {
*/
void Dialog::appendText(const char *line) {
_lineX += strlen(line);
- _widthX += _vm->_font->getWidth(line, DIALOG_SPACING);
+ _widthX += _vm->_font->current()->getWidth(line, DIALOG_SPACING);
strcat(_lines[_lines.size() - 1].data, line);
}
@@ -158,7 +158,7 @@ void Dialog::addLine(const char *line, bool underlineP) {
if ((_widthX > 0) || (_lineX > 0))
incLine();
- int lineWidth = _vm->_font->getWidth(line, DIALOG_SPACING);
+ int lineWidth = _vm->_font->current()->getWidth(line, DIALOG_SPACING);
int lineLen = strlen(line);
if ((lineWidth > _dialogWidth) || (lineLen >= _widthChars))
@@ -383,7 +383,7 @@ Dialog::Dialog(MadsM4Engine *vm, const char *msgData, const char *title): View(v
if (id > 0) {
// Suffix provided - specifies the dialog width in number of chars
_widthChars = id * 2;
- _dialogWidth = id * (_vm->_font->getMaxWidth() + DIALOG_SPACING) + 10;
+ _dialogWidth = id * (_vm->_font->current()->getMaxWidth() + DIALOG_SPACING) + 10;
}
} else if (matchCommand(cmdText, "UNDER")) {
@@ -416,7 +416,7 @@ Dialog::Dialog(MadsM4Engine *vm, const char *msgData, const char *title): View(v
Dialog::Dialog(MadsM4Engine *vm, int widthChars): View(vm, Common::Rect(0, 0, 0, 0)) {
_vm->_font->setFont(FONT_INTERFACE_MADS);
_widthChars = widthChars * 2;
- _dialogWidth = widthChars * (_vm->_font->getMaxWidth() + DIALOG_SPACING) + 10;
+ _dialogWidth = widthChars * (_vm->_font->current()->getMaxWidth() + DIALOG_SPACING) + 10;
_screenType = LAYER_DIALOG;
_lineX = 0;
_widthX = 0;
@@ -439,7 +439,7 @@ void Dialog::draw() {
// Calculate bounds
int dlgWidth = _dialogWidth;
- int dlgHeight = _lines.size() * (_vm->_font->getHeight() + 1) + 10;
+ int dlgHeight = _lines.size() * (_vm->_font->current()->getHeight() + 1) + 10;
int dialogX = (_vm->_screen->width() - dlgWidth) / 2;
int dialogY = (_vm->_screen->height() - dlgHeight) / 2;
@@ -480,26 +480,26 @@ void Dialog::draw() {
}
// Handle drawing the text contents
- _vm->_font->setColours(7, 7, 7);
+ _vm->_font->current()->setColours(7, 7, 7);
setColour(7);
- for (uint lineCtr = 0, yp = 5; lineCtr < _lines.size(); ++lineCtr, yp += _vm->_font->getHeight() + 1) {
+ for (uint lineCtr = 0, yp = 5; lineCtr < _lines.size(); ++lineCtr, yp += _vm->_font->current()->getHeight() + 1) {
if (_lines[lineCtr].barLine) {
// Bar separation line
- hLine(5, width() - 6, ((_vm->_font->getHeight() + 1) >> 1) + yp);
+ hLine(5, width() - 6, ((_vm->_font->current()->getHeight() + 1) >> 1) + yp);
} else {
// Standard line
Common::Point pt(_lines[lineCtr].xp + 5, yp);
if (_lines[lineCtr].xp & 0x40)
++pt.y;
- _vm->_font->writeString(this, _lines[lineCtr].data, pt.x, pt.y, 0, DIALOG_SPACING);
+ _vm->_font->current()->writeString(this, _lines[lineCtr].data, pt.x, pt.y, 0, DIALOG_SPACING);
if (_lines[lineCtr].underline)
// Underline needed
- hLine(pt.x, pt.x + _vm->_font->getWidth(_lines[lineCtr].data, DIALOG_SPACING),
- pt.y + _vm->_font->getHeight());
+ hLine(pt.x, pt.x + _vm->_font->current()->getWidth(_lines[lineCtr].data, DIALOG_SPACING),
+ pt.y + _vm->_font->current()->getHeight());
}
}
@@ -528,7 +528,7 @@ void Dialog::display(MadsM4Engine *vm, int widthChars, const char **descEntries)
dlg->incLine();
dlg->writeChars(*descEntries);
- int lineWidth = vm->_font->getWidth(*descEntries, DIALOG_SPACING);
+ int lineWidth = vm->_font->current()->getWidth(*descEntries, DIALOG_SPACING);
dlg->_lines[dlg->_lines.size() - 1].xp = (dlg->_dialogWidth - 10 - lineWidth) / 2;
++descEntries;
}
diff --git a/engines/m4/globals.h b/engines/m4/globals.h
index 2bfedf1449..3fc31b4ec2 100644
--- a/engines/m4/globals.h
+++ b/engines/m4/globals.h
@@ -276,6 +276,7 @@ public:
// DEPRECATED: ScummVM re-implementation keeps all the quotes loaded, so the methods below are stubs
void clearQuotes() {}
void loadQuoteRange(int startNum, int endNum) {}
+ void loadQuoteSet(...) {}
void loadQuote(int quoteNum) {}
void loadMadsMessagesInfo();
diff --git a/engines/m4/gui.cpp b/engines/m4/gui.cpp
index 8f949de9c5..8665b4e767 100644
--- a/engines/m4/gui.cpp
+++ b/engines/m4/gui.cpp
@@ -290,26 +290,26 @@ void MenuButton::onRefresh() {
case OBJTYPE_SL_TEXT:
switch (_objectState) {
case OS_MOUSEOVER:
- _vm->_font->setColors(TEXT_COLOR_MOUSEOVER_SHADOW, TEXT_COLOR_MOUSEOVER_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_MOUSEOVER_SHADOW, TEXT_COLOR_MOUSEOVER_FOREGROUND,
TEXT_COLOR_MOUSEOVER_HILIGHT);
sprite = sprites[SL_LINE_MOUSEOVER];
break;
case OS_PRESSED:
- _vm->_font->setColors(TEXT_COLOR_PRESSED_SHADOW, TEXT_COLOR_PRESSED_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_PRESSED_SHADOW, TEXT_COLOR_PRESSED_FOREGROUND,
TEXT_COLOR_PRESSED_HILIGHT);
sprite = sprites[SL_LINE_PRESSED];
break;
case OS_GREYED:
- _vm->_font->setColors(TEXT_COLOR_GREYED_SHADOW, TEXT_COLOR_GREYED_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_GREYED_SHADOW, TEXT_COLOR_GREYED_FOREGROUND,
TEXT_COLOR_GREYED_HILIGHT);
sprite = sprites[SL_LINE_NORMAL];
break;
default:
case OS_NORMAL:
- _vm->_font->setColors(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
TEXT_COLOR_NORMAL_HILIGHT);
sprite = sprites[SL_LINE_NORMAL];
break;
@@ -849,11 +849,11 @@ void MenuSaveLoadText::onRefresh() {
if (_displayValue != 0) {
char tempBuffer[5];
sprintf(tempBuffer, "%02d", _displayValue);
- _vm->_font->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->current()->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
xp = _bounds.left + 26;
}
- _vm->_font->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->current()->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
}
}
@@ -955,18 +955,18 @@ void MenuTextField::onRefresh() {
// Draw the text
_vm->_font->setFont(FONT_MENU);
- _vm->_font->setColors(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
+ _vm->_font->current()->setColours(TEXT_COLOR_NORMAL_SHADOW, TEXT_COLOR_NORMAL_FOREGROUND,
TEXT_COLOR_NORMAL_HILIGHT);
int xp = _bounds.left + 4;
if (_displayValue != 0) {
char tempBuffer[5];
sprintf(tempBuffer, "%02d", _displayValue);
- _vm->_font->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->current()->writeString(_parent, tempBuffer, xp, _bounds.top + 1, 0, -1);
xp = _bounds.left + 26;
}
- _vm->_font->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
+ _vm->_font->current()->writeString(_parent, _displayText, xp, _bounds.top + 1, 0, -1);
if (focused) {
// Draw in the cursor
@@ -975,7 +975,7 @@ void MenuTextField::onRefresh() {
// Get the width of the string up to the cursor position
char tempCh = *_cursor;
*_cursor = '\0';
- int stringWidth = _vm->_font->getWidth(_displayText);
+ int stringWidth = _vm->_font->current()->getWidth(_displayText);
*_cursor = tempCh;
parent()->setColor(TEXT_COLOR_MOUSEOVER_FOREGROUND);
@@ -1015,10 +1015,10 @@ bool MenuTextField::onEvent(M4EventType event, int32 param, int x, int y, MenuOb
tempP = &tempStr[tempLen];
_vm->_font->setFont(FONT_MENU);
- tempLen = _vm->_font->getWidth(tempStr);
+ tempLen = _vm->_font->current()->getWidth(tempStr);
while ((tempP != &tempStr[0]) && (tempLen > x - _bounds.left - 26)) {
*--tempP = '\0';
- tempLen = _vm->_font->getWidth(tempStr);
+ tempLen = _vm->_font->current()->getWidth(tempStr);
}
_cursor = &_displayText[tempP - &tempStr[0]];
@@ -1098,7 +1098,7 @@ bool MenuTextField::onEvent(M4EventType event, int32 param, int x, int y, MenuOb
parent()->_deleteSaveDesc = false;
_vm->_font->setFont(FONT_MENU);
- tempLen = _vm->_font->getWidth(_displayText);
+ tempLen = _vm->_font->current()->getWidth(_displayText);
if ((strlen(_displayText) < MAX_SAVEGAME_NAME - 1) &&
(tempLen < _pixelWidth - 12) && (param >= 32) && (param <= 127)) {
@@ -1140,9 +1140,9 @@ GUITextField::GUITextField(View *owner, const Common::Rect &bounds): GUIRect(own
void GUITextField::onRefresh() {
_parent->fillRect(_bounds, _vm->_palette->BLACK);
- _vm->_font->setColors(3, 3, 3);
+ _vm->_font->current()->setColours(3, 3, 3);
_vm->_font->setFont(FONT_INTERFACE);
- _vm->_font->writeString(_parent, _text.c_str(), _bounds.left, _bounds.top, 0, 1);
+ _vm->_font->current()->writeString(_parent, _text.c_str(), _bounds.left, _bounds.top, 0, 1);
}
//--------------------------------------------------------------------------
diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp
index 824896ad33..a999a6bd5a 100644
--- a/engines/m4/m4.cpp
+++ b/engines/m4/m4.cpp
@@ -145,7 +145,6 @@ MadsM4Engine::~MadsM4Engine() {
delete _script;
delete _ws;
delete _random;
- delete _animation;
delete _palette;
delete _globals;
delete _sound;
@@ -174,7 +173,7 @@ Common::Error MadsM4Engine::run() {
_events = new Events(this);
_kernel = new Kernel(this);
_player = new Player(this);
- _font = new Font(this);
+ _font = new FontManager(this);
if (getGameType() == GType_Burger) {
_actor = new Actor(this);
_conversationView = new ConversationView(this);
@@ -188,7 +187,6 @@ Common::Error MadsM4Engine::run() {
_sound = new Sound(this, _mixer, 255);
_script = new ScriptInterpreter(this);
_ws = new WoodScript(this);
- _animation = new Animation(this);
//_callbacks = new Callbacks(this);
_random = new Common::RandomSource();
g_eventRec.registerRandomSource(*_random, "m4");
@@ -557,9 +555,9 @@ Common::Error MadsEngine::run() {
_scene->show();
_font->setFont(FONT_MAIN_MADS);
- _font->setColors(2, 1, 3);
- _font->writeString(_scene->getBackgroundSurface(), "Testing the M4/MADS ScummVM engine", 5, 160, 310, 2);
- _font->writeString(_scene->getBackgroundSurface(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5, 180, 310, 2);
+ _font->current()->setColours(2, 1, 3);
+ _font->current()->writeString(_scene->getBackgroundSurface(), "Testing the M4/MADS ScummVM engine", 5, 160, 310, 2);
+ _font->current()->writeString(_scene->getBackgroundSurface(), "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 5, 180, 310, 2);
if (getGameType() == GType_DragonSphere) {
//_scene->showMADSV2TextBox("Test", 10, 10, NULL);
@@ -575,8 +573,6 @@ Common::Error MadsEngine::run() {
while (!_events->quitFlag) {
eventHandler();
- _animation->updateAnim();
-
if (g_system->getMillis() >= nextFrame) {
nextFrame = g_system->getMillis() + GAME_FRAME_DELAY;
++_currentTimer;
diff --git a/engines/m4/m4.h b/engines/m4/m4.h
index 9e3035957a..3174c886d5 100644
--- a/engines/m4/m4.h
+++ b/engines/m4/m4.h
@@ -192,7 +192,7 @@ public:
Player *_player;
Mouse *_mouse;
Events *_events;
- Font *_font;
+ FontManager *_font;
Actor *_actor;
Scene *_scene;
Dialogs *_dialogs;
@@ -203,7 +203,6 @@ public:
Rails *_rails;
ScriptInterpreter *_script;
WoodScript *_ws;
- Animation *_animation;
Common::RandomSource *_random;
Scene *scene() { return _scene; }
diff --git a/engines/m4/m4_views.cpp b/engines/m4/m4_views.cpp
index 3d633cef0d..f4345787df 100644
--- a/engines/m4/m4_views.cpp
+++ b/engines/m4/m4_views.cpp
@@ -34,7 +34,7 @@ namespace M4 {
GUIInventory::GUIInventory(View *owner, MadsM4Engine *vm, const Common::Rect &bounds, int horizCells,
int vertCells, int cellWidth, int cellHeight, int tag): GUIRect(owner, bounds, tag) {
- _vm = vm;
+ _vm = vm;
_cellCount.x = horizCells;
_cellCount.y = vertCells;
_cellSize.x = cellWidth;
diff --git a/engines/m4/mads_anim.cpp b/engines/m4/mads_anim.cpp
index 5e19e90533..ca53bdca75 100644
--- a/engines/m4/mads_anim.cpp
+++ b/engines/m4/mads_anim.cpp
@@ -37,7 +37,7 @@ namespace M4 {
TextviewView::TextviewView(MadsM4Engine *vm):
View(vm, Common::Rect(0, 0, vm->_screen->width(), vm->_screen->height())),
_bgSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT),
- _textSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT + vm->_font->getHeight() +
+ _textSurface(vm->_screen->width(), MADS_SURFACE_HEIGHT + vm->_font->current()->getHeight() +
TEXTVIEW_LINE_SPACING) {
_screenType = VIEWID_TEXTVIEW;
@@ -60,7 +60,7 @@ TextviewView::TextviewView(MadsM4Engine *vm):
_vm->_palette->setPalette(&palData[0], 4, 3);
_vm->_palette->blockRange(4, 3);
- _vm->_font->setColors(5, 6, 4);
+ _vm->_font->current()->setColours(5, 6, 4);
clear();
_bgSurface.clear();
@@ -222,7 +222,7 @@ void TextviewView::updateState() {
}
} else {
// Handling a text row
- if (++_lineY == (_vm->_font->getHeight() + TEXTVIEW_LINE_SPACING))
+ if (++_lineY == (_vm->_font->current()->getHeight() + TEXTVIEW_LINE_SPACING))
processLines();
}
@@ -404,7 +404,7 @@ void TextviewView::processText() {
if (!strcmp(_currentLine, "***")) {
// Special signifier for end of script
- _scrollCount = _vm->_font->getHeight() * 13;
+ _scrollCount = _vm->_font->current()->getHeight() * 13;
_lineY = -1;
return;
}
@@ -416,7 +416,7 @@ void TextviewView::processText() {
char *centerP = strchr(_currentLine, '@');
if (centerP) {
*centerP = '\0';
- xStart = (width() / 2) - _vm->_font->getWidth(_currentLine);
+ xStart = (width() / 2) - _vm->_font->current()->getWidth(_currentLine);
// Delete the @ character and shift back the remainder of the string
char *p = centerP + 1;
@@ -424,16 +424,16 @@ void TextviewView::processText() {
strcpy(centerP, p);
} else {
- lineWidth = _vm->_font->getWidth(_currentLine);
+ lineWidth = _vm->_font->current()->getWidth(_currentLine);
xStart = (width() - lineWidth) / 2;
}
// Copy the text line onto the bottom of the textSurface surface, which will allow it
// to gradually scroll onto the screen
- int yp = _textSurface.height() - _vm->_font->getHeight() - TEXTVIEW_LINE_SPACING;
+ int yp = _textSurface.height() - _vm->_font->current()->getHeight() - TEXTVIEW_LINE_SPACING;
_textSurface.fillRect(Common::Rect(0, yp, _textSurface.width(), _textSurface.height()),
_vm->_palette->BLACK);
- _vm->_font->writeString(&_textSurface, _currentLine, xStart, yp);
+ _vm->_font->current()->writeString(&_textSurface, _currentLine, xStart, yp);
}
diff --git a/engines/m4/mads_menus.cpp b/engines/m4/mads_menus.cpp
index 1ee6b3d265..810acb04fb 100644
--- a/engines/m4/mads_menus.cpp
+++ b/engines/m4/mads_menus.cpp
@@ -617,10 +617,10 @@ void RexDialogView::initialiseLines() {
}
_totalTextEntries = 0;
- // Set up a default sprite slot entry
+ // Set up a default sprite slot entry for a full screen refresh
_spriteSlots.startIndex = 1;
- _spriteSlots[0].spriteId = -2;
- _spriteSlots[0].timerIndex = -1;
+ _spriteSlots[0].spriteType = FULL_SCREEN_REFRESH;
+ _spriteSlots[0].seqIndex = -1;
}
void RexDialogView::initialiseGraphics() {
@@ -796,8 +796,8 @@ bool RexDialogView::onEvent(M4EventType eventType, int32 param1, int x, int y, b
void RexDialogView::setFrame(int frameNumber, int depth) {
int slotIndex = _spriteSlots.getIndex();
- _spriteSlots[slotIndex].spriteId = 1;
- _spriteSlots[slotIndex].timerIndex = 1;
+ _spriteSlots[slotIndex].spriteType = FOREGROUND_SPRITE;
+ _spriteSlots[slotIndex].seqIndex = 1;
_spriteSlots[slotIndex].spriteListIndex = 0; //_menuSpritesIndex;
_spriteSlots[slotIndex].frameNumber = frameNumber;
@@ -986,15 +986,15 @@ RexGameMenuDialog::RexGameMenuDialog(): RexDialogView() {
void RexGameMenuDialog::addLines() {
// Add the title
- int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->getHeight() + 2) * 6) >> 1) - 78);
+ int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 2) * 6) >> 1) - 78);
- addQuote(_vm->_font, ALIGN_CENTER, 0, top, 10);
+ addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 10);
// Loop for adding the option lines of the dialog
top += 6;
for (int idx = 0; idx < 5; ++idx) {
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CENTER, 0, top, 11 + idx);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 11 + idx);
}
}
@@ -1070,42 +1070,42 @@ void RexOptionsDialog::reload() {
void RexOptionsDialog::addLines() {
// Add the title
- int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->getHeight() + 1) * 9 + 12) >> 1) - 78);
+ int top = MADS_Y_OFFSET - 2 - ((((_vm->_font->current()->getHeight() + 1) * 9 + 12) >> 1) - 78);
- addQuote(_vm->_font, ALIGN_CENTER, 0, top, 16);
+ addQuote(_vm->_font->current(), ALIGN_CENTER, 0, top, 16);
// Music state line
- top += _vm->_font->getHeight() + 1 + 6;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 17, _tempConfig.musicFlag ? 24 : 25);
+ top += _vm->_font->current()->getHeight() + 1 + 6;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 17, _tempConfig.musicFlag ? 24 : 25);
// Sound state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 18, _tempConfig.soundFlag ? 26 : 27);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 18, _tempConfig.soundFlag ? 26 : 27);
// Interface easy state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 19, _tempConfig.easyMouse ? 29 : 28);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 19, _tempConfig.easyMouse ? 29 : 28);
// Inventory sppinng state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 20, _tempConfig.invObjectsStill ? 31 : 30);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 20, _tempConfig.invObjectsStill ? 31 : 30);
// Text window state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 21, _tempConfig.textWindowStill ? 33 : 32);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 21, _tempConfig.textWindowStill ? 33 : 32);
// Screen fade state line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 22, _tempConfig.screenFades + 34);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 22, _tempConfig.screenFades + 34);
// Storyline mode line
- top += _vm->_font->getHeight() + 1;
- addQuote(_vm->_font, ALIGN_CHAR_CENTER, 0, top, 23, (_tempConfig.storyMode == 1) ? 37 : 38);
+ top += _vm->_font->current()->getHeight() + 1;
+ addQuote(_vm->_font->current(), ALIGN_CHAR_CENTER, 0, top, 23, (_tempConfig.storyMode == 1) ? 37 : 38);
// Add Done and Cancel button texts
- top += _vm->_font->getHeight() + 1 + 6;
- addQuote(_vm->_font, ALIGN_CENTER, -54, top, 1, 0);
- addQuote(_vm->_font, ALIGN_CENTER, 54, top, 2, 0);
+ top += _vm->_font->current()->getHeight() + 1 + 6;
+ addQuote(_vm->_font->current(), ALIGN_CENTER, -54, top, 1, 0);
+ addQuote(_vm->_font->current(), ALIGN_CENTER, 54, top, 2, 0);
}
bool RexOptionsDialog::onEvent(M4EventType eventType, int32 param1, int x, int y, bool &captureEvents) {
diff --git a/engines/mohawk/video/cinepak.cpp b/engines/mohawk/video/cinepak.cpp
deleted file mode 100644
index 2ffe6869ae..0000000000
--- a/engines/mohawk/video/cinepak.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "mohawk/video/cinepak.h"
-
-#include "common/system.h"
-#include "graphics/conversion.h" // For YUV2RGB
-
-// Code here partially based off of ffmpeg ;)
-
-namespace Mohawk {
-
-#define PUT_PIXEL(offset, lum, u, v) \
- Graphics::CPYUV2RGB(lum, u, v, r, g, b); \
- if (_pixelFormat.bytesPerPixel == 2) \
- *((uint16 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b); \
- else \
- *((uint32 *)_curFrame.surface->pixels + offset) = _pixelFormat.RGBToColor(r, g, b)
-
-CinepakDecoder::CinepakDecoder() : Graphics::Codec() {
- _curFrame.surface = NULL;
- _curFrame.strips = NULL;
- _y = 0;
- _pixelFormat = g_system->getScreenFormat();
-
- // We're going to have to dither if we're running in 8bpp.
- // We'll take RGBA8888 for best color performance in this case.
- if (_pixelFormat.bytesPerPixel == 1)
- _pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
-}
-
-CinepakDecoder::~CinepakDecoder() {
- if (_curFrame.surface)
- _curFrame.surface->free();
- delete[] _curFrame.strips;
-}
-
-Graphics::Surface *CinepakDecoder::decodeImage(Common::SeekableReadStream *stream) {
- _curFrame.flags = stream->readByte();
- _curFrame.length = (stream->readByte() << 16) + stream->readUint16BE();
- _curFrame.width = stream->readUint16BE();
- _curFrame.height = stream->readUint16BE();
- _curFrame.stripCount = stream->readUint16BE();
-
- if (_curFrame.strips == NULL)
- _curFrame.strips = new CinepakStrip[_curFrame.stripCount];
-
- debug (4, "Cinepak Frame: Width = %d, Height = %d, Strip Count = %d", _curFrame.width, _curFrame.height, _curFrame.stripCount);
-
-#if 0
- // Borrowed from FFMPEG. This should cut out the extra data Cinepak for Sega has (which is useless).
- // The theory behind this is that this is here to confuse standard Cinepak decoders. But, we won't let that happen! ;)
- if (_curFrame.length != (uint32)stream->size()) {
- if (stream->readUint16BE() == 0xFE00)
- stream->readUint32BE();
- }
-#endif
-
- if (!_curFrame.surface) {
- _curFrame.surface = new Graphics::Surface();
- _curFrame.surface->create(_curFrame.width, _curFrame.height, _pixelFormat.bytesPerPixel);
- }
-
- // Reset the y variable.
- _y = 0;
-
- for (uint16 i = 0; i < _curFrame.stripCount; i++) {
- if (i > 0 && !(_curFrame.flags & 1)) { // Use codebooks from last strip
- for (uint16 j = 0; j < 256; j++) {
- _curFrame.strips[i].v1_codebook[j] = _curFrame.strips[i - 1].v1_codebook[j];
- _curFrame.strips[i].v4_codebook[j] = _curFrame.strips[i - 1].v4_codebook[j];
- }
- }
-
- _curFrame.strips[i].id = stream->readUint16BE();
- _curFrame.strips[i].length = stream->readUint16BE() - 12; // Subtract the 12 byte header
- _curFrame.strips[i].rect.top = _y; stream->readUint16BE(); // Ignore, substitute with our own.
- _curFrame.strips[i].rect.left = 0; stream->readUint16BE(); // Ignore, substitute with our own
- _curFrame.strips[i].rect.bottom = _y + stream->readUint16BE();
- _curFrame.strips[i].rect.right = _curFrame.width; stream->readUint16BE(); // Ignore, substitute with our own
-
- //printf ("Left = %d, Top = %d, Right = %d, Bottom = %d\n", _curFrame.strips[i].rect.left, _curFrame.strips[i].rect.top, _curFrame.strips[i].rect.right, _curFrame.strips[i].rect.bottom);
-
- // Sanity check. Because Cinepak is based on 4x4 blocks, the width and height of each strip needs to be divisible by 4.
- assert(!(_curFrame.strips[i].rect.width() % 4) && !(_curFrame.strips[i].rect.height() % 4));
-
- uint32 pos = stream->pos();
-
- while ((uint32)stream->pos() < (pos + _curFrame.strips[i].length) && !stream->eos()) {
- byte chunkID = stream->readByte();
-
- if (stream->eos())
- break;
-
- // Chunk Size is 24-bit, ignore the first 4 bytes
- uint32 chunkSize = stream->readByte() << 16;
- chunkSize += stream->readUint16BE() - 4;
-
- int32 startPos = stream->pos();
-
- switch (chunkID) {
- case 0x20:
- case 0x21:
- case 0x24:
- case 0x25:
- loadCodebook(stream, i, 4, chunkID, chunkSize);
- break;
- case 0x22:
- case 0x23:
- case 0x26:
- case 0x27:
- loadCodebook(stream, i, 1, chunkID, chunkSize);
- break;
- case 0x30:
- case 0x31:
- case 0x32:
- decodeVectors(stream, i, chunkID, chunkSize);
- break;
- default:
- warning("Unknown Cinepak chunk ID %02x", chunkID);
- return _curFrame.surface;
- }
-
- if (stream->pos() != startPos + (int32)chunkSize)
- stream->seek(startPos + chunkSize);
- }
-
- _y = _curFrame.strips[i].rect.bottom;
- }
-
- return _curFrame.surface;
-}
-
-void CinepakDecoder::loadCodebook(Common::SeekableReadStream *stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize) {
- CinepakCodebook *codebook = (codebookType == 1) ? _curFrame.strips[strip].v1_codebook : _curFrame.strips[strip].v4_codebook;
-
- int32 startPos = stream->pos();
- uint32 flag = 0, mask = 0;
-
- for (uint16 i = 0; i < 256; i++) {
- if ((chunkID & 0x01) && !(mask >>= 1)) {
- if ((stream->pos() - startPos + 4) > (int32)chunkSize)
- break;
-
- flag = stream->readUint32BE();
- mask = 0x80000000;
- }
-
- if (!(chunkID & 0x01) || (flag & mask)) {
- byte n = (chunkID & 0x04) ? 4 : 6;
- if ((stream->pos() - startPos + n) > (int32)chunkSize)
- break;
-
- for (byte j = 0; j < 4; j++)
- codebook[i].y[j] = stream->readByte();
-
- if (n == 6) {
- codebook[i].u = stream->readByte() + 128;
- codebook[i].v = stream->readByte() + 128;
- } else {
- /* this codebook type indicates either greyscale or
- * palettized video; if palettized, U & V components will
- * not be used so it is safe to set them to 128 for the
- * benefit of greyscale rendering in YUV420P */
- codebook[i].u = 128;
- codebook[i].v = 128;
- }
- }
- }
-}
-
-void CinepakDecoder::decodeVectors(Common::SeekableReadStream *stream, uint16 strip, byte chunkID, uint32 chunkSize) {
- uint32 flag = 0, mask = 0;
- uint32 iy[4];
- int32 startPos = stream->pos();
- byte r = 0, g = 0, b = 0;
-
- for (uint16 y = _curFrame.strips[strip].rect.top; y < _curFrame.strips[strip].rect.bottom; y += 4) {
- iy[0] = _curFrame.strips[strip].rect.left + y * _curFrame.width;
- iy[1] = iy[0] + _curFrame.width;
- iy[2] = iy[1] + _curFrame.width;
- iy[3] = iy[2] + _curFrame.width;
-
- for (uint16 x = _curFrame.strips[strip].rect.left; x < _curFrame.strips[strip].rect.right; x += 4) {
- if ((chunkID & 0x01) && !(mask >>= 1)) {
- if ((stream->pos() - startPos + 4) > (int32)chunkSize)
- return;
-
- flag = stream->readUint32BE();
- mask = 0x80000000;
- }
-
- if (!(chunkID & 0x01) || (flag & mask)) {
- if (!(chunkID & 0x02) && !(mask >>= 1)) {
- if ((stream->pos() - startPos + 4) > (int32)chunkSize)
- return;
-
- flag = stream->readUint32BE();
- mask = 0x80000000;
- }
-
- if ((chunkID & 0x02) || (~flag & mask)) {
- if ((stream->pos() - startPos + 1) > (int32)chunkSize)
- return;
-
- // Get the codebook
- CinepakCodebook codebook = _curFrame.strips[strip].v1_codebook[stream->readByte()];
-
- PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 1, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 1, codebook.y[0], codebook.u, codebook.v);
-
- PUT_PIXEL(iy[0] + 2, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 2, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 3, codebook.y[1], codebook.u, codebook.v);
-
- PUT_PIXEL(iy[2] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 1, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 1, codebook.y[2], codebook.u, codebook.v);
-
- PUT_PIXEL(iy[2] + 2, codebook.y[3], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 3, codebook.y[3], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 2, codebook.y[3], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
- } else if (flag & mask) {
- if ((stream->pos() - startPos + 4) > (int32)chunkSize)
- return;
-
- CinepakCodebook codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
- PUT_PIXEL(iy[0] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 1, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 1, codebook.y[3], codebook.u, codebook.v);
-
- codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
- PUT_PIXEL(iy[0] + 2, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[0] + 3, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 2, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[1] + 3, codebook.y[3], codebook.u, codebook.v);
-
- codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
- PUT_PIXEL(iy[2] + 0, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 1, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 0, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 1, codebook.y[3], codebook.u, codebook.v);
-
- codebook = _curFrame.strips[strip].v4_codebook[stream->readByte()];
- PUT_PIXEL(iy[2] + 2, codebook.y[0], codebook.u, codebook.v);
- PUT_PIXEL(iy[2] + 3, codebook.y[1], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 2, codebook.y[2], codebook.u, codebook.v);
- PUT_PIXEL(iy[3] + 3, codebook.y[3], codebook.u, codebook.v);
- }
- }
-
- for (byte i = 0; i < 4; i++)
- iy[i] += 4;
- }
- }
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/cinepak.h b/engines/mohawk/video/cinepak.h
deleted file mode 100644
index 3f4cbba17c..0000000000
--- a/engines/mohawk/video/cinepak.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef CINEPAK_H
-#define CINEPAK_H
-
-#include "common/scummsys.h"
-#include "common/stream.h"
-#include "common/rect.h"
-#include "graphics/surface.h"
-#include "graphics/pixelformat.h"
-
-#include "graphics/video/codecs/codec.h"
-
-namespace Mohawk {
-
-struct CinepakCodebook {
- byte y[4];
- byte u, v;
-};
-
-struct CinepakStrip {
- uint16 id;
- uint16 length;
- Common::Rect rect;
- CinepakCodebook v1_codebook[256], v4_codebook[256];
-};
-
-struct CinepakFrame {
- byte flags;
- uint32 length;
- uint16 width;
- uint16 height;
- uint16 stripCount;
- CinepakStrip *strips;
-
- Graphics::Surface *surface;
-};
-
-class CinepakDecoder : public Graphics::Codec {
-public:
- CinepakDecoder();
- ~CinepakDecoder();
-
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
- Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
-
-private:
- CinepakFrame _curFrame;
- int32 _y;
- Graphics::PixelFormat _pixelFormat;
-
- void loadCodebook(Common::SeekableReadStream *stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize);
- void decodeVectors(Common::SeekableReadStream *stream, uint16 strip, byte chunkID, uint32 chunkSize);
-};
-
-}
-
-#endif
diff --git a/engines/mohawk/video/qdm2.cpp b/engines/mohawk/video/qdm2.cpp
deleted file mode 100644
index b91440f00d..0000000000
--- a/engines/mohawk/video/qdm2.cpp
+++ /dev/null
@@ -1,3063 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-// Based off ffmpeg's QDM2 decoder
-
-#include "mohawk/video/qdm2.h"
-#include "mohawk/video/qdm2data.h"
-
-#include "common/system.h"
-
-namespace Mohawk {
-
-// Fix compilation for non C99-compliant compilers, like MSVC
-#ifndef int64_t
-typedef signed long long int int64_t;
-#endif
-
-// Integer log2 function. This is much faster than invoking
-// double precision C99 log2 math functions or equivalent, since
-// this is only used to determine maximum number of bits needed
-// i.e. only non-fractional part is needed. Also, the double
-// version is incorrect for exact cases due to floating point
-// rounding errors.
-static inline int scummvm_log2(int n) {
- int ret = -1;
- while(n != 0) {
- n /= 2;
- ret++;
- }
- return ret;
-}
-
-#define QDM2_LIST_ADD(list, size, packet) \
- do { \
- if (size > 0) \
- list[size - 1].next = &list[size]; \
- list[size].packet = packet; \
- list[size].next = NULL; \
- size++; \
- } while(0)
-
-// Result is 8, 16 or 30
-#define QDM2_SB_USED(subSampling) (((subSampling) >= 2) ? 30 : 8 << (subSampling))
-
-#define FIX_NOISE_IDX(noiseIdx) \
- if ((noiseIdx) >= 3840) \
- (noiseIdx) -= 3840 \
-
-#define SB_DITHERING_NOISE(sb, noiseIdx) (_noiseTable[(noiseIdx)++] * sb_noise_attenuation[(sb)])
-
-static inline void initGetBits(GetBitContext *s, const uint8 *buffer, int bitSize) {
- int bufferSize = (bitSize + 7) >> 3;
-
- debug(1, "void initGetBits(GetBitContext *s, const uint8 *buffer, int bitSize)");
-
- if (bufferSize < 0 || bitSize < 0) {
- bufferSize = bitSize = 0;
- buffer = NULL;
- }
-
- s->buffer = buffer;
- s->sizeInBits = bitSize;
- s->bufferEnd = buffer + bufferSize;
- s->index = 0;
-}
-
-static inline int getBitsCount(GetBitContext *s) {
- debug(1, "int getBitsCount(GetBitContext *s)");
- return s->index;
-}
-
-static inline unsigned int getBits1(GetBitContext *s) {
- int index;
- uint8 result;
-
- debug(1, "unsigned int getBits1(GetBitContext *s)");
-
- index = s->index;
- result = s->buffer[index >> 3];
-
- debug(1, "index : %d", index);
-
- result >>= (index & 0x07);
- result &= 1;
- index++;
- s->index = index;
-
- return result;
-}
-
-static inline unsigned int getBits(GetBitContext *s, int n) {
- int tmp, reCache, reIndex;
-
- debug(1, "unsigned int getBits(GetBitContext *s, int n)");
-
- reIndex = s->index;
-
- debug(1, "reIndex : %d", reIndex);
-
- reCache = READ_LE_UINT32((const uint8 *)s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
-
- tmp = (reCache) & ((uint32)0xffffffff >> (32 - n));
-
- s->index = reIndex + n;
-
- return tmp;
-}
-
-static inline void skipBits(GetBitContext *s, int n) {
- int reIndex, reCache;
-
- debug(1, "void skipBits(GetBitContext *s, int n)");
-
- reIndex = s->index;
- reCache = 0;
-
- debug(1, "reIndex : %d", reIndex);
-
- reCache = READ_LE_UINT32((const uint8 *)s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
- s->index = reIndex + n;
-}
-
-#define BITS_LEFT(length, gb) ((length) - getBitsCount((gb)))
-
-static int splitRadixPermutation(int i, int n, int inverse) {
- if (n <= 2)
- return i & 1;
-
- int m = n >> 1;
-
- if(!(i & m))
- return splitRadixPermutation(i, m, inverse) * 2;
-
- m >>= 1;
-
- if (inverse == !(i & m))
- return splitRadixPermutation(i, m, inverse) * 4 + 1;
-
- return splitRadixPermutation(i, m, inverse) * 4 - 1;
-}
-
-// sin(2*pi*x/n) for 0<=x<n/4, followed by n/2<=x<3n/4
-float ff_sin_16[8];
-float ff_sin_32[16];
-float ff_sin_64[32];
-float ff_sin_128[64];
-float ff_sin_256[128];
-float ff_sin_512[256];
-float ff_sin_1024[512];
-float ff_sin_2048[1024];
-float ff_sin_4096[2048];
-float ff_sin_8192[4096];
-float ff_sin_16384[8192];
-float ff_sin_32768[16384];
-float ff_sin_65536[32768];
-
-float *ff_sin_tabs[] = {
- NULL, NULL, NULL, NULL,
- ff_sin_16, ff_sin_32, ff_sin_64, ff_sin_128, ff_sin_256, ff_sin_512, ff_sin_1024,
- ff_sin_2048, ff_sin_4096, ff_sin_8192, ff_sin_16384, ff_sin_32768, ff_sin_65536,
-};
-
-// cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse
-float ff_cos_16[8];
-float ff_cos_32[16];
-float ff_cos_64[32];
-float ff_cos_128[64];
-float ff_cos_256[128];
-float ff_cos_512[256];
-float ff_cos_1024[512];
-float ff_cos_2048[1024];
-float ff_cos_4096[2048];
-float ff_cos_8192[4096];
-float ff_cos_16384[8192];
-float ff_cos_32768[16384];
-float ff_cos_65536[32768];
-
-float *ff_cos_tabs[] = {
- NULL, NULL, NULL, NULL,
- ff_cos_16, ff_cos_32, ff_cos_64, ff_cos_128, ff_cos_256, ff_cos_512, ff_cos_1024,
- ff_cos_2048, ff_cos_4096, ff_cos_8192, ff_cos_16384, ff_cos_32768, ff_cos_65536,
-};
-
-void initCosineTables(int index) {
- int m = 1 << index;
- double freq = 2 * PI / m;
- float *tab = ff_cos_tabs[index];
-
- for (int i = 0; i <= m / 4; i++)
- tab[i] = cos(i * freq);
-
- for (int i = 1; i < m / 4; i++)
- tab[m / 2 - i] = tab[i];
-}
-
-void fftPermute(FFTContext *s, FFTComplex *z) {
- const uint16 *revtab = s->revtab;
- int np = 1 << s->nbits;
-
- if (s->tmpBuf) {
- // TODO: handle split-radix permute in a more optimal way, probably in-place
- for (int j = 0; j < np; j++)
- s->tmpBuf[revtab[j]] = z[j];
- memcpy(z, s->tmpBuf, np * sizeof(FFTComplex));
- return;
- }
-
- // reverse
- for (int j = 0; j < np; j++) {
- int k = revtab[j];
- if (k < j) {
- FFTComplex tmp = z[k];
- z[k] = z[j];
- z[j] = tmp;
- }
- }
-}
-
-#define DECL_FFT(n,n2,n4) \
-static void fft##n(FFTComplex *z) { \
- fft##n2(z); \
- fft##n4(z + n4 * 2); \
- fft##n4(z + n4 * 3); \
- pass(z, ff_cos_##n, n4 / 2); \
-}
-
-#ifndef M_SQRT1_2
-#define M_SQRT1_2 7.0710678118654752440E-1
-#endif
-
-#define sqrthalf (float)M_SQRT1_2
-
-#define BF(x,y,a,b) { \
- x = a - b; \
- y = a + b; \
-}
-
-#define BUTTERFLIES(a0, a1, a2, a3) { \
- BF(t3, t5, t5, t1); \
- BF(a2.re, a0.re, a0.re, t5); \
- BF(a3.im, a1.im, a1.im, t3); \
- BF(t4, t6, t2, t6); \
- BF(a3.re, a1.re, a1.re, t4); \
- BF(a2.im, a0.im, a0.im, t6); \
-}
-
-// force loading all the inputs before storing any.
-// this is slightly slower for small data, but avoids store->load aliasing
-// for addresses separated by large powers of 2.
-#define BUTTERFLIES_BIG(a0, a1, a2, a3) { \
- float r0 = a0.re, i0 = a0.im, r1 = a1.re, i1 = a1.im; \
- BF(t3, t5, t5, t1); \
- BF(a2.re, a0.re, r0, t5); \
- BF(a3.im, a1.im, i1, t3); \
- BF(t4, t6, t2, t6); \
- BF(a3.re, a1.re, r1, t4); \
- BF(a2.im, a0.im, i0, t6); \
-}
-
-#define TRANSFORM(a0, a1, a2, a3, wre, wim) { \
- t1 = a2.re * wre + a2.im * wim; \
- t2 = a2.im * wre - a2.re * wim; \
- t5 = a3.re * wre - a3.im * wim; \
- t6 = a3.im * wre + a3.re * wim; \
- BUTTERFLIES(a0, a1, a2, a3) \
-}
-
-#define TRANSFORM_ZERO(a0, a1, a2, a3) { \
- t1 = a2.re; \
- t2 = a2.im; \
- t5 = a3.re; \
- t6 = a3.im; \
- BUTTERFLIES(a0, a1, a2, a3) \
-}
-
-// z[0...8n-1], w[1...2n-1]
-#define PASS(name) \
-static void name(FFTComplex *z, const float *wre, unsigned int n) { \
- float t1, t2, t3, t4, t5, t6; \
- int o1 = 2 * n; \
- int o2 = 4 * n; \
- int o3 = 6 * n; \
- const float *wim = wre + o1; \
- n--; \
- \
- TRANSFORM_ZERO(z[0], z[o1], z[o2], z[o3]); \
- TRANSFORM(z[1], z[o1 + 1], z[o2 + 1], z[o3 + 1], wre[1], wim[-1]); \
- \
- do { \
- z += 2; \
- wre += 2; \
- wim -= 2; \
- TRANSFORM(z[0], z[o1], z[o2], z[o3], wre[0], wim[0]); \
- TRANSFORM(z[1], z[o1 + 1],z[o2 + 1], z[o3 + 1], wre[1], wim[-1]); \
- } while(--n); \
-}
-
-PASS(pass)
-#undef BUTTERFLIES
-#define BUTTERFLIES BUTTERFLIES_BIG
-PASS(pass_big)
-
-static void fft4(FFTComplex *z) {
- float t1, t2, t3, t4, t5, t6, t7, t8;
-
- BF(t3, t1, z[0].re, z[1].re);
- BF(t8, t6, z[3].re, z[2].re);
- BF(z[2].re, z[0].re, t1, t6);
- BF(t4, t2, z[0].im, z[1].im);
- BF(t7, t5, z[2].im, z[3].im);
- BF(z[3].im, z[1].im, t4, t8);
- BF(z[3].re, z[1].re, t3, t7);
- BF(z[2].im, z[0].im, t2, t5);
-}
-
-static void fft8(FFTComplex *z) {
- float t1, t2, t3, t4, t5, t6, t7, t8;
-
- fft4(z);
-
- BF(t1, z[5].re, z[4].re, -z[5].re);
- BF(t2, z[5].im, z[4].im, -z[5].im);
- BF(t3, z[7].re, z[6].re, -z[7].re);
- BF(t4, z[7].im, z[6].im, -z[7].im);
- BF(t8, t1, t3, t1);
- BF(t7, t2, t2, t4);
- BF(z[4].re, z[0].re, z[0].re, t1);
- BF(z[4].im, z[0].im, z[0].im, t2);
- BF(z[6].re, z[2].re, z[2].re, t7);
- BF(z[6].im, z[2].im, z[2].im, t8);
-
- TRANSFORM(z[1], z[3], z[5], z[7], sqrthalf, sqrthalf);
-}
-
-#undef BF
-
-DECL_FFT(16,8,4)
-DECL_FFT(32,16,8)
-DECL_FFT(64,32,16)
-DECL_FFT(128,64,32)
-DECL_FFT(256,128,64)
-DECL_FFT(512,256,128)
-#define pass pass_big
-DECL_FFT(1024,512,256)
-DECL_FFT(2048,1024,512)
-DECL_FFT(4096,2048,1024)
-DECL_FFT(8192,4096,2048)
-DECL_FFT(16384,8192,4096)
-DECL_FFT(32768,16384,8192)
-DECL_FFT(65536,32768,16384)
-
-void fftCalc(FFTContext *s, FFTComplex *z) {
- static void (* const fftDispatch[])(FFTComplex*) = {
- fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024,
- fft2048, fft4096, fft8192, fft16384, fft32768, fft65536,
- };
-
- fftDispatch[s->nbits - 2](z);
-}
-
-// complex multiplication: p = a * b
-#define CMUL(pre, pim, are, aim, bre, bim) \
-{\
- float _are = (are); \
- float _aim = (aim); \
- float _bre = (bre); \
- float _bim = (bim); \
- (pre) = _are * _bre - _aim * _bim; \
- (pim) = _are * _bim + _aim * _bre; \
-}
-
-/**
- * Compute the middle half of the inverse MDCT of size N = 2^nbits,
- * thus excluding the parts that can be derived by symmetry
- * @param output N/2 samples
- * @param input N/2 samples
- */
-void imdctHalfC(FFTContext *s, float *output, const float *input) {
- const uint16 *revtab = s->revtab;
- const float *tcos = s->tcos;
- const float *tsin = s->tsin;
- FFTComplex *z = (FFTComplex *)output;
-
- int n = 1 << s->mdctBits;
- int n2 = n >> 1;
- int n4 = n >> 2;
- int n8 = n >> 3;
-
- // pre rotation
- const float *in1 = input;
- const float *in2 = input + n2 - 1;
- for (int k = 0; k < n4; k++) {
- int j = revtab[k];
- CMUL(z[j].re, z[j].im, *in2, *in1, tcos[k], tsin[k]);
- in1 += 2;
- in2 -= 2;
- }
-
- fftCalc(s, z);
-
- // post rotation + reordering
- for (int k = 0; k < n8; k++) {
- float r0, i0, r1, i1;
- CMUL(r0, i1, z[n8 - k - 1].im, z[n8 - k - 1].re, tsin[n8 - k - 1], tcos[n8 - k - 1]);
- CMUL(r1, i0, z[n8 + k].im, z[n8 + k].re, tsin[n8 + k], tcos[n8 + k]);
- z[n8 - k - 1].re = r0;
- z[n8 - k - 1].im = i0;
- z[n8 + k].re = r1;
- z[n8 + k].im = i1;
- }
-}
-
-/**
- * Compute inverse MDCT of size N = 2^nbits
- * @param output N samples
- * @param input N/2 samples
- */
-void imdctCalcC(FFTContext *s, float *output, const float *input) {
- int n = 1 << s->mdctBits;
- int n2 = n >> 1;
- int n4 = n >> 2;
-
- imdctHalfC(s, output + n4, input);
-
- for (int k = 0; k < n4; k++) {
- output[k] = -output[n2 - k - 1];
- output[n - k - 1] = output[n2 + k];
- }
-}
-
-/**
- * Compute MDCT of size N = 2^nbits
- * @param input N samples
- * @param out N/2 samples
- */
-void mdctCalcC(FFTContext *s, float *out, const float *input) {
- const uint16 *revtab = s->revtab;
- const float *tcos = s->tcos;
- const float *tsin = s->tsin;
- FFTComplex *x = (FFTComplex *)out;
-
- int n = 1 << s->mdctBits;
- int n2 = n >> 1;
- int n4 = n >> 2;
- int n8 = n >> 3;
- int n3 = 3 * n4;
-
- // pre rotation
- for (int i = 0; i < n8; i++) {
- float re = -input[2 * i + 3 * n4] - input[n3 - 1 - 2 * i];
- float im = -input[n4 + 2 * i] + input[n4 - 1 - 2 * i];
- int j = revtab[i];
- CMUL(x[j].re, x[j].im, re, im, -tcos[i], tsin[i]);
-
- re = input[2 * i] - input[n2 - 1 - 2 * i];
- im = -(input[n2 + 2 * i] + input[n - 1 - 2 * i]);
- j = revtab[n8 + i];
- CMUL(x[j].re, x[j].im, re, im, -tcos[n8 + i], tsin[n8 + i]);
- }
-
- fftCalc(s, x);
-
- // post rotation
- for (int i = 0; i < n8; i++) {
- float r0, i0, r1, i1;
- CMUL(i1, r0, x[n8 - i - 1].re, x[n8 - i - 1].im, -tsin[n8 - i - 1], -tcos[n8 - i - 1]);
- CMUL(i0, r1, x[n8 + i].re, x[n8 + i].im, -tsin[n8 + i], -tcos[n8 + i]);
- x[n8 - i - 1].re = r0;
- x[n8 - i - 1].im = i0;
- x[n8 + i].re = r1;
- x[n8 + i].im = i1;
- }
-}
-
-int fftInit(FFTContext *s, int nbits, int inverse) {
- int i, j, m, n;
- float alpha, c1, s1, s2;
-
- if (nbits < 2 || nbits > 16)
- goto fail;
-
- s->nbits = nbits;
- n = 1 << nbits;
- s->tmpBuf = NULL;
-
- s->exptab = (FFTComplex *)malloc((n / 2) * sizeof(FFTComplex));
- if (!s->exptab)
- goto fail;
-
- s->revtab = (uint16 *)malloc(n * sizeof(uint16));
- if (!s->revtab)
- goto fail;
- s->inverse = inverse;
-
- s2 = inverse ? 1.0 : -1.0;
-
- s->fftPermute = fftPermute;
- s->fftCalc = fftCalc;
- s->imdctCalc = imdctCalcC;
- s->imdctHalf = imdctHalfC;
- s->mdctCalc = mdctCalcC;
- s->splitRadix = 1;
-
- if (s->splitRadix) {
- for (j = 4; j <= nbits; j++)
- initCosineTables(j);
-
- for (i = 0; i < n; i++)
- s->revtab[-splitRadixPermutation(i, n, s->inverse) & (n - 1)] = i;
-
- s->tmpBuf = (FFTComplex *)malloc(n * sizeof(FFTComplex));
- } else {
- for (i = 0; i < n / 2; i++) {
- alpha = 2 * PI * (float)i / (float)n;
- c1 = cos(alpha);
- s1 = sin(alpha) * s2;
- s->exptab[i].re = c1;
- s->exptab[i].im = s1;
- }
-
- //int np = 1 << nbits;
- //int nblocks = np >> 3;
- //int np2 = np >> 1;
-
- // compute bit reverse table
- for (i = 0; i < n; i++) {
- m = 0;
-
- for (j = 0; j < nbits; j++)
- m |= ((i >> j) & 1) << (nbits - j - 1);
-
- s->revtab[i] = m;
- }
- }
-
- return 0;
-
- fail:
- free(&s->revtab);
- free(&s->exptab);
- free(&s->tmpBuf);
- return -1;
-}
-
-/**
- * Sets up a real FFT.
- * @param nbits log2 of the length of the input array
- * @param trans the type of transform
- */
-int rdftInit(RDFTContext *s, int nbits, RDFTransformType trans) {
- int n = 1 << nbits;
- const double theta = (trans == RDFT || trans == IRIDFT ? -1 : 1) * 2 * PI / n;
-
- s->nbits = nbits;
- s->inverse = trans == IRDFT || trans == IRIDFT;
- s->signConvention = trans == RIDFT || trans == IRIDFT ? 1 : -1;
-
- if (nbits < 4 || nbits > 16)
- return -1;
-
- if (fftInit(&s->fft, nbits - 1, trans == IRDFT || trans == RIDFT) < 0)
- return -1;
-
- initCosineTables(nbits);
- s->tcos = ff_cos_tabs[nbits];
- s->tsin = ff_sin_tabs[nbits] + (trans == RDFT || trans == IRIDFT) * (n >> 2);
-
- for (int i = 0; i < n >> 2; i++)
- s->tsin[i] = sin(i*theta);
-
- return 0;
-}
-
-/** Map one real FFT into two parallel real even and odd FFTs. Then interleave
- * the two real FFTs into one complex FFT. Unmangle the results.
- * ref: http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM
- */
-void rdftCalc(RDFTContext *s, float *data) {
- FFTComplex ev, od;
-
- const int n = 1 << s->nbits;
- const float k1 = 0.5;
- const float k2 = 0.5 - s->inverse;
- const float *tcos = s->tcos;
- const float *tsin = s->tsin;
-
- if (!s->inverse) {
- fftPermute(&s->fft, (FFTComplex *)data);
- fftCalc(&s->fft, (FFTComplex *)data);
- }
-
- // i=0 is a special case because of packing, the DC term is real, so we
- // are going to throw the N/2 term (also real) in with it.
- ev.re = data[0];
- data[0] = ev.re + data[1];
- data[1] = ev.re - data[1];
-
- int i;
-
- for (i = 1; i < n >> 2; i++) {
- int i1 = i * 2;
- int i2 = n - i1;
-
- // Separate even and odd FFTs
- ev.re = k1 * (data[i1] + data[i2]);
- od.im = -k2 * (data[i1] - data[i2]);
- ev.im = k1 * (data[i1 + 1] - data[i2 + 1]);
- od.re = k2 * (data[i1 + 1] + data[i2 + 1]);
-
- // Apply twiddle factors to the odd FFT and add to the even FFT
- data[i1] = ev.re + od.re * tcos[i] - od.im * tsin[i];
- data[i1 + 1] = ev.im + od.im * tcos[i] + od.re * tsin[i];
- data[i2] = ev.re - od.re * tcos[i] + od.im * tsin[i];
- data[i2 + 1] = -ev.im + od.im * tcos[i] + od.re * tsin[i];
- }
-
- data[i * 2 + 1] = s->signConvention * data[i * 2 + 1];
- if (s->inverse) {
- data[0] *= k1;
- data[1] *= k1;
- fftPermute(&s->fft, (FFTComplex*)data);
- fftCalc(&s->fft, (FFTComplex*)data);
- }
-}
-
-// half mpeg encoding window (full precision)
-const int32 ff_mpa_enwindow[257] = {
- 0, -1, -1, -1, -1, -1, -1, -2,
- -2, -2, -2, -3, -3, -4, -4, -5,
- -5, -6, -7, -7, -8, -9, -10, -11,
- -13, -14, -16, -17, -19, -21, -24, -26,
- -29, -31, -35, -38, -41, -45, -49, -53,
- -58, -63, -68, -73, -79, -85, -91, -97,
- -104, -111, -117, -125, -132, -139, -147, -154,
- -161, -169, -176, -183, -190, -196, -202, -208,
- 213, 218, 222, 225, 227, 228, 228, 227,
- 224, 221, 215, 208, 200, 189, 177, 163,
- 146, 127, 106, 83, 57, 29, -2, -36,
- -72, -111, -153, -197, -244, -294, -347, -401,
- -459, -519, -581, -645, -711, -779, -848, -919,
- -991, -1064, -1137, -1210, -1283, -1356, -1428, -1498,
- -1567, -1634, -1698, -1759, -1817, -1870, -1919, -1962,
- -2001, -2032, -2057, -2075, -2085, -2087, -2080, -2063,
- 2037, 2000, 1952, 1893, 1822, 1739, 1644, 1535,
- 1414, 1280, 1131, 970, 794, 605, 402, 185,
- -45, -288, -545, -814, -1095, -1388, -1692, -2006,
- -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788,
- -5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597,
- -7910, -8209, -8491, -8755, -8998, -9219, -9416, -9585,
- -9727, -9838, -9916, -9959, -9966, -9935, -9863, -9750,
- -9592, -9389, -9139, -8840, -8492, -8092, -7640, -7134,
- 6574, 5959, 5288, 4561, 3776, 2935, 2037, 1082,
- 70, -998, -2122, -3300, -4533, -5818, -7154, -8540,
- -9975,-11455,-12980,-14548,-16155,-17799,-19478,-21189,
--22929,-24694,-26482,-28289,-30112,-31947,-33791,-35640,
--37489,-39336,-41176,-43006,-44821,-46617,-48390,-50137,
--51853,-53534,-55178,-56778,-58333,-59838,-61289,-62684,
--64019,-65290,-66494,-67629,-68692,-69679,-70590,-71420,
--72169,-72835,-73415,-73908,-74313,-74630,-74856,-74992,
- 75038
-};
-
-void ff_mpa_synth_init(int16 *window) {
- int i;
- int32 v;
-
- // max = 18760, max sum over all 16 coefs : 44736
- for(i = 0; i < 257; i++) {
- v = ff_mpa_enwindow[i];
- v = (v + 2) >> 2;
- window[i] = v;
-
- if ((i & 63) != 0)
- v = -v;
-
- if (i != 0)
- window[512 - i] = v;
- }
-}
-
-static inline uint16 round_sample(int *sum) {
- int sum1;
- sum1 = (*sum) >> 14;
- *sum &= (1 << 14)-1;
- if (sum1 < (-0x7fff - 1))
- sum1 = (-0x7fff - 1);
- if (sum1 > 0x7fff)
- sum1 = 0x7fff;
- return sum1;
-}
-
-static inline int MULH(int a, int b) {
- return ((int64_t)(a) * (int64_t)(b))>>32;
-}
-
-// signed 16x16 -> 32 multiply add accumulate
-#define MACS(rt, ra, rb) rt += (ra) * (rb)
-
-#define MLSS(rt, ra, rb) ((rt) -= (ra) * (rb))
-
-#define SUM8(op, sum, w, p)\
-{\
- op(sum, (w)[0 * 64], (p)[0 * 64]);\
- op(sum, (w)[1 * 64], (p)[1 * 64]);\
- op(sum, (w)[2 * 64], (p)[2 * 64]);\
- op(sum, (w)[3 * 64], (p)[3 * 64]);\
- op(sum, (w)[4 * 64], (p)[4 * 64]);\
- op(sum, (w)[5 * 64], (p)[5 * 64]);\
- op(sum, (w)[6 * 64], (p)[6 * 64]);\
- op(sum, (w)[7 * 64], (p)[7 * 64]);\
-}
-
-#define SUM8P2(sum1, op1, sum2, op2, w1, w2, p) \
-{\
- tmp_s = p[0 * 64];\
- op1(sum1, (w1)[0 * 64], tmp_s);\
- op2(sum2, (w2)[0 * 64], tmp_s);\
- tmp_s = p[1 * 64];\
- op1(sum1, (w1)[1 * 64], tmp_s);\
- op2(sum2, (w2)[1 * 64], tmp_s);\
- tmp_s = p[2 * 64];\
- op1(sum1, (w1)[2 * 64], tmp_s);\
- op2(sum2, (w2)[2 * 64], tmp_s);\
- tmp_s = p[3 * 64];\
- op1(sum1, (w1)[3 * 64], tmp_s);\
- op2(sum2, (w2)[3 * 64], tmp_s);\
- tmp_s = p[4 * 64];\
- op1(sum1, (w1)[4 * 64], tmp_s);\
- op2(sum2, (w2)[4 * 64], tmp_s);\
- tmp_s = p[5 * 64];\
- op1(sum1, (w1)[5 * 64], tmp_s);\
- op2(sum2, (w2)[5 * 64], tmp_s);\
- tmp_s = p[6 * 64];\
- op1(sum1, (w1)[6 * 64], tmp_s);\
- op2(sum2, (w2)[6 * 64], tmp_s);\
- tmp_s = p[7 * 64];\
- op1(sum1, (w1)[7 * 64], tmp_s);\
- op2(sum2, (w2)[7 * 64], tmp_s);\
-}
-
-#define FIXHR(a) ((int)((a) * (1LL<<32) + 0.5))
-
-// tab[i][j] = 1.0 / (2.0 * cos(pi*(2*k+1) / 2^(6 - j)))
-
-// cos(i*pi/64)
-
-#define COS0_0 FIXHR(0.50060299823519630134/2)
-#define COS0_1 FIXHR(0.50547095989754365998/2)
-#define COS0_2 FIXHR(0.51544730992262454697/2)
-#define COS0_3 FIXHR(0.53104259108978417447/2)
-#define COS0_4 FIXHR(0.55310389603444452782/2)
-#define COS0_5 FIXHR(0.58293496820613387367/2)
-#define COS0_6 FIXHR(0.62250412303566481615/2)
-#define COS0_7 FIXHR(0.67480834145500574602/2)
-#define COS0_8 FIXHR(0.74453627100229844977/2)
-#define COS0_9 FIXHR(0.83934964541552703873/2)
-#define COS0_10 FIXHR(0.97256823786196069369/2)
-#define COS0_11 FIXHR(1.16943993343288495515/4)
-#define COS0_12 FIXHR(1.48416461631416627724/4)
-#define COS0_13 FIXHR(2.05778100995341155085/8)
-#define COS0_14 FIXHR(3.40760841846871878570/8)
-#define COS0_15 FIXHR(10.19000812354805681150/32)
-
-#define COS1_0 FIXHR(0.50241928618815570551/2)
-#define COS1_1 FIXHR(0.52249861493968888062/2)
-#define COS1_2 FIXHR(0.56694403481635770368/2)
-#define COS1_3 FIXHR(0.64682178335999012954/2)
-#define COS1_4 FIXHR(0.78815462345125022473/2)
-#define COS1_5 FIXHR(1.06067768599034747134/4)
-#define COS1_6 FIXHR(1.72244709823833392782/4)
-#define COS1_7 FIXHR(5.10114861868916385802/16)
-
-#define COS2_0 FIXHR(0.50979557910415916894/2)
-#define COS2_1 FIXHR(0.60134488693504528054/2)
-#define COS2_2 FIXHR(0.89997622313641570463/2)
-#define COS2_3 FIXHR(2.56291544774150617881/8)
-
-#define COS3_0 FIXHR(0.54119610014619698439/2)
-#define COS3_1 FIXHR(1.30656296487637652785/4)
-
-#define COS4_0 FIXHR(0.70710678118654752439/2)
-
-/* butterfly operator */
-#define BF(a, b, c, s)\
-{\
- tmp0 = tab[a] + tab[b];\
- tmp1 = tab[a] - tab[b];\
- tab[a] = tmp0;\
- tab[b] = MULH(tmp1<<(s), c);\
-}
-
-#define BF1(a, b, c, d)\
-{\
- BF(a, b, COS4_0, 1);\
- BF(c, d,-COS4_0, 1);\
- tab[c] += tab[d];\
-}
-
-#define BF2(a, b, c, d)\
-{\
- BF(a, b, COS4_0, 1);\
- BF(c, d,-COS4_0, 1);\
- tab[c] += tab[d];\
- tab[a] += tab[c];\
- tab[c] += tab[b];\
- tab[b] += tab[d];\
-}
-
-#define ADD(a, b) tab[a] += tab[b]
-
-// DCT32 without 1/sqrt(2) coef zero scaling.
-static void dct32(int32 *out, int32 *tab) {
- int tmp0, tmp1;
-
- // pass 1
- BF( 0, 31, COS0_0 , 1);
- BF(15, 16, COS0_15, 5);
- // pass 2
- BF( 0, 15, COS1_0 , 1);
- BF(16, 31,-COS1_0 , 1);
- // pass 1
- BF( 7, 24, COS0_7 , 1);
- BF( 8, 23, COS0_8 , 1);
- // pass 2
- BF( 7, 8, COS1_7 , 4);
- BF(23, 24,-COS1_7 , 4);
- // pass 3
- BF( 0, 7, COS2_0 , 1);
- BF( 8, 15,-COS2_0 , 1);
- BF(16, 23, COS2_0 , 1);
- BF(24, 31,-COS2_0 , 1);
- // pass 1
- BF( 3, 28, COS0_3 , 1);
- BF(12, 19, COS0_12, 2);
- // pass 2
- BF( 3, 12, COS1_3 , 1);
- BF(19, 28,-COS1_3 , 1);
- // pass 1
- BF( 4, 27, COS0_4 , 1);
- BF(11, 20, COS0_11, 2);
- // pass 2
- BF( 4, 11, COS1_4 , 1);
- BF(20, 27,-COS1_4 , 1);
- // pass 3
- BF( 3, 4, COS2_3 , 3);
- BF(11, 12,-COS2_3 , 3);
- BF(19, 20, COS2_3 , 3);
- BF(27, 28,-COS2_3 , 3);
- // pass 4
- BF( 0, 3, COS3_0 , 1);
- BF( 4, 7,-COS3_0 , 1);
- BF( 8, 11, COS3_0 , 1);
- BF(12, 15,-COS3_0 , 1);
- BF(16, 19, COS3_0 , 1);
- BF(20, 23,-COS3_0 , 1);
- BF(24, 27, COS3_0 , 1);
- BF(28, 31,-COS3_0 , 1);
-
- // pass 1
- BF( 1, 30, COS0_1 , 1);
- BF(14, 17, COS0_14, 3);
- // pass 2
- BF( 1, 14, COS1_1 , 1);
- BF(17, 30,-COS1_1 , 1);
- // pass 1
- BF( 6, 25, COS0_6 , 1);
- BF( 9, 22, COS0_9 , 1);
- // pass 2
- BF( 6, 9, COS1_6 , 2);
- BF(22, 25,-COS1_6 , 2);
- // pass 3
- BF( 1, 6, COS2_1 , 1);
- BF( 9, 14,-COS2_1 , 1);
- BF(17, 22, COS2_1 , 1);
- BF(25, 30,-COS2_1 , 1);
-
- // pass 1
- BF( 2, 29, COS0_2 , 1);
- BF(13, 18, COS0_13, 3);
- // pass 2
- BF( 2, 13, COS1_2 , 1);
- BF(18, 29,-COS1_2 , 1);
- // pass 1
- BF( 5, 26, COS0_5 , 1);
- BF(10, 21, COS0_10, 1);
- // pass 2
- BF( 5, 10, COS1_5 , 2);
- BF(21, 26,-COS1_5 , 2);
- // pass 3
- BF( 2, 5, COS2_2 , 1);
- BF(10, 13,-COS2_2 , 1);
- BF(18, 21, COS2_2 , 1);
- BF(26, 29,-COS2_2 , 1);
- // pass 4
- BF( 1, 2, COS3_1 , 2);
- BF( 5, 6,-COS3_1 , 2);
- BF( 9, 10, COS3_1 , 2);
- BF(13, 14,-COS3_1 , 2);
- BF(17, 18, COS3_1 , 2);
- BF(21, 22,-COS3_1 , 2);
- BF(25, 26, COS3_1 , 2);
- BF(29, 30,-COS3_1 , 2);
-
- // pass 5
- BF1( 0, 1, 2, 3);
- BF2( 4, 5, 6, 7);
- BF1( 8, 9, 10, 11);
- BF2(12, 13, 14, 15);
- BF1(16, 17, 18, 19);
- BF2(20, 21, 22, 23);
- BF1(24, 25, 26, 27);
- BF2(28, 29, 30, 31);
-
- // pass 6
- ADD( 8, 12);
- ADD(12, 10);
- ADD(10, 14);
- ADD(14, 9);
- ADD( 9, 13);
- ADD(13, 11);
- ADD(11, 15);
-
- out[ 0] = tab[0];
- out[16] = tab[1];
- out[ 8] = tab[2];
- out[24] = tab[3];
- out[ 4] = tab[4];
- out[20] = tab[5];
- out[12] = tab[6];
- out[28] = tab[7];
- out[ 2] = tab[8];
- out[18] = tab[9];
- out[10] = tab[10];
- out[26] = tab[11];
- out[ 6] = tab[12];
- out[22] = tab[13];
- out[14] = tab[14];
- out[30] = tab[15];
-
- ADD(24, 28);
- ADD(28, 26);
- ADD(26, 30);
- ADD(30, 25);
- ADD(25, 29);
- ADD(29, 27);
- ADD(27, 31);
-
- out[ 1] = tab[16] + tab[24];
- out[17] = tab[17] + tab[25];
- out[ 9] = tab[18] + tab[26];
- out[25] = tab[19] + tab[27];
- out[ 5] = tab[20] + tab[28];
- out[21] = tab[21] + tab[29];
- out[13] = tab[22] + tab[30];
- out[29] = tab[23] + tab[31];
- out[ 3] = tab[24] + tab[20];
- out[19] = tab[25] + tab[21];
- out[11] = tab[26] + tab[22];
- out[27] = tab[27] + tab[23];
- out[ 7] = tab[28] + tab[18];
- out[23] = tab[29] + tab[19];
- out[15] = tab[30] + tab[17];
- out[31] = tab[31];
-}
-
-// 32 sub band synthesis filter. Input: 32 sub band samples, Output:
-// 32 samples.
-// XXX: optimize by avoiding ring buffer usage
-void ff_mpa_synth_filter(int16 *synth_buf_ptr, int *synth_buf_offset,
- int16 *window, int *dither_state,
- int16 *samples, int incr,
- int32 sb_samples[32])
-{
- int16 *synth_buf;
- const int16 *w, *w2, *p;
- int j, offset;
- int16 *samples2;
- int32 tmp[32];
- int sum, sum2;
- int tmp_s;
-
- offset = *synth_buf_offset;
- synth_buf = synth_buf_ptr + offset;
-
- dct32(tmp, sb_samples);
- for(j = 0; j < 32; j++) {
- // NOTE: can cause a loss in precision if very high amplitude sound
- if (tmp[j] < (-0x7fff - 1))
- synth_buf[j] = (-0x7fff - 1);
- else if (tmp[j] > 0x7fff)
- synth_buf[j] = 0x7fff;
- else
- synth_buf[j] = tmp[j];
- }
-
- // copy to avoid wrap
- memcpy(synth_buf + 512, synth_buf, 32 * sizeof(int16));
-
- samples2 = samples + 31 * incr;
- w = window;
- w2 = window + 31;
-
- sum = *dither_state;
- p = synth_buf + 16;
- SUM8(MACS, sum, w, p);
- p = synth_buf + 48;
- SUM8(MLSS, sum, w + 32, p);
- *samples = round_sample(&sum);
- samples += incr;
- w++;
-
- // we calculate two samples at the same time to avoid one memory
- // access per two sample
- for(j = 1; j < 16; j++) {
- sum2 = 0;
- p = synth_buf + 16 + j;
- SUM8P2(sum, MACS, sum2, MLSS, w, w2, p);
- p = synth_buf + 48 - j;
- SUM8P2(sum, MLSS, sum2, MLSS, w + 32, w2 + 32, p);
-
- *samples = round_sample(&sum);
- samples += incr;
- sum += sum2;
- *samples2 = round_sample(&sum);
- samples2 -= incr;
- w++;
- w2--;
- }
-
- p = synth_buf + 32;
- SUM8(MLSS, sum, w + 32, p);
- *samples = round_sample(&sum);
- *dither_state= sum;
-
- offset = (offset - 32) & 511;
- *synth_buf_offset = offset;
-}
-
-/**
- * parses a vlc code, faster then get_vlc()
- * @param bits is the number of bits which will be read at once, must be
- * identical to nb_bits in init_vlc()
- * @param max_depth is the number of times bits bits must be read to completely
- * read the longest vlc code
- * = (max_vlc_length + bits - 1) / bits
- */
-static int getVlc2(GetBitContext *s, int16 (*table)[2], int bits, int maxDepth) {
- int reIndex;
- int reCache;
- int index;
- int code;
- int n;
-
- debug(1, "int getVlc2(GetBitContext *s, int16 (*table)[2], int bits, int maxDepth)");
-
- reIndex = s->index;
- reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
- index = reCache & (0xffffffff >> (32 - bits));
- code = table[index][0];
- n = table[index][1];
-
- debug(1, "reIndex : %d", reIndex);
- debug(1, "reCache : %d", reCache);
- debug(1, "index : %d", index);
- debug(1, "code : %d", code);
- debug(1, "n : %d", n);
-
- if (maxDepth > 1 && n < 0){
- reIndex += bits;
- reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
-
- int nbBits = -n;
-
- index = (reCache & (0xffffffff >> (32 - nbBits))) + code;
- code = table[index][0];
- n = table[index][1];
-
- if(maxDepth > 2 && n < 0) {
- reIndex += nbBits;
- reCache = READ_LE_UINT32(s->buffer + (reIndex >> 3)) >> (reIndex & 0x07);
-
- nbBits = -n;
-
- index = (reCache & (0xffffffff >> (32 - nbBits))) + code;
- code = table[index][0];
- n = table[index][1];
- }
- }
-
- reCache >>= n;
- s->index = reIndex + n;
- return code;
-}
-
-static int allocTable(VLC *vlc, int size, int use_static) {
- int index;
- index = vlc->table_size;
- vlc->table_size += size;
- if (vlc->table_size > vlc->table_allocated) {
- if(use_static)
- error("QDM2 cant do anything, init_vlc() is used with too little memory");
- vlc->table_allocated += (1 << vlc->bits);
- vlc->table = (int16 (*)[2])realloc(vlc->table, sizeof(int16 *) * 2 * vlc->table_allocated);
- if (!vlc->table)
- return -1;
- }
- return index;
-}
-
-#define GET_DATA(v, table, i, wrap, size)\
-{\
- const uint8 *ptr = (const uint8 *)table + i * wrap;\
- switch(size) {\
- case 1:\
- v = *(const uint8 *)ptr;\
- break;\
- case 2:\
- v = *(const uint16 *)ptr;\
- break;\
- default:\
- v = *(const uint32 *)ptr;\
- break;\
- }\
-}
-
-static int build_table(VLC *vlc, int table_nb_bits,
- int nb_codes,
- const void *bits, int bits_wrap, int bits_size,
- const void *codes, int codes_wrap, int codes_size,
- const void *symbols, int symbols_wrap, int symbols_size,
- int code_prefix, int n_prefix, int flags)
-{
- int i, j, k, n, table_size, table_index, nb, n1, index, code_prefix2, symbol;
- uint32 code;
- int16 (*table)[2];
-
- table_size = 1 << table_nb_bits;
- table_index = allocTable(vlc, table_size, flags & 4);
- debug(2, "QDM2 new table index=%d size=%d code_prefix=%x n=%d", table_index, table_size, code_prefix, n_prefix);
- if (table_index < 0)
- return -1;
- table = &vlc->table[table_index];
-
- for(i = 0; i < table_size; i++) {
- table[i][1] = 0; //bits
- table[i][0] = -1; //codes
- }
-
- // first pass: map codes and compute auxillary table sizes
- for(i = 0; i < nb_codes; i++) {
- GET_DATA(n, bits, i, bits_wrap, bits_size);
- GET_DATA(code, codes, i, codes_wrap, codes_size);
- // we accept tables with holes
- if (n <= 0)
- continue;
- if (!symbols)
- symbol = i;
- else
- GET_DATA(symbol, symbols, i, symbols_wrap, symbols_size);
- debug(2, "QDM2 i=%d n=%d code=0x%x", i, n, code);
- // if code matches the prefix, it is in the table
- n -= n_prefix;
- if(flags & 2)
- code_prefix2= code & (n_prefix>=32 ? 0xffffffff : (1 << n_prefix)-1);
- else
- code_prefix2= code >> n;
- if (n > 0 && code_prefix2 == code_prefix) {
- if (n <= table_nb_bits) {
- // no need to add another table
- j = (code << (table_nb_bits - n)) & (table_size - 1);
- nb = 1 << (table_nb_bits - n);
- for(k = 0; k < nb; k++) {
- if(flags & 2)
- j = (code >> n_prefix) + (k<<n);
- debug(2, "QDM2 %4x: code=%d n=%d",j, i, n);
- if (table[j][1] /*bits*/ != 0) {
- error("QDM2 incorrect codes");
- return -1;
- }
- table[j][1] = n; //bits
- table[j][0] = symbol;
- j++;
- }
- } else {
- n -= table_nb_bits;
- j = (code >> ((flags & 2) ? n_prefix : n)) & ((1 << table_nb_bits) - 1);
- debug(2, "QDM2 %4x: n=%d (subtable)", j, n);
- // compute table size
- n1 = -table[j][1]; //bits
- if (n > n1)
- n1 = n;
- table[j][1] = -n1; //bits
- }
- }
- }
-
- // second pass : fill auxillary tables recursively
- for(i = 0;i < table_size; i++) {
- n = table[i][1]; //bits
- if (n < 0) {
- n = -n;
- if (n > table_nb_bits) {
- n = table_nb_bits;
- table[i][1] = -n; //bits
- }
- index = build_table(vlc, n, nb_codes,
- bits, bits_wrap, bits_size,
- codes, codes_wrap, codes_size,
- symbols, symbols_wrap, symbols_size,
- (flags & 2) ? (code_prefix | (i << n_prefix)) : ((code_prefix << table_nb_bits) | i),
- n_prefix + table_nb_bits, flags);
- if (index < 0)
- return -1;
- // note: realloc has been done, so reload tables
- table = &vlc->table[table_index];
- table[i][0] = index; //code
- }
- }
- return table_index;
-}
-
-/* Build VLC decoding tables suitable for use with get_vlc().
-
- 'nb_bits' set thee decoding table size (2^nb_bits) entries. The
- bigger it is, the faster is the decoding. But it should not be too
- big to save memory and L1 cache. '9' is a good compromise.
-
- 'nb_codes' : number of vlcs codes
-
- 'bits' : table which gives the size (in bits) of each vlc code.
-
- 'codes' : table which gives the bit pattern of of each vlc code.
-
- 'symbols' : table which gives the values to be returned from get_vlc().
-
- 'xxx_wrap' : give the number of bytes between each entry of the
- 'bits' or 'codes' tables.
-
- 'xxx_size' : gives the number of bytes of each entry of the 'bits'
- or 'codes' tables.
-
- 'wrap' and 'size' allows to use any memory configuration and types
- (byte/word/long) to store the 'bits', 'codes', and 'symbols' tables.
-
- 'use_static' should be set to 1 for tables, which should be freed
- with av_free_static(), 0 if free_vlc() will be used.
-*/
-void initVlcSparse(VLC *vlc, int nb_bits, int nb_codes,
- const void *bits, int bits_wrap, int bits_size,
- const void *codes, int codes_wrap, int codes_size,
- const void *symbols, int symbols_wrap, int symbols_size) {
- vlc->bits = nb_bits;
-
- if(vlc->table_size && vlc->table_size == vlc->table_allocated) {
- return;
- } else if(vlc->table_size) {
- error("called on a partially initialized table");
- }
-
- debug(2, "QDM2 build table nb_codes=%d", nb_codes);
-
- if (build_table(vlc, nb_bits, nb_codes,
- bits, bits_wrap, bits_size,
- codes, codes_wrap, codes_size,
- symbols, symbols_wrap, symbols_size,
- 0, 0, 4 | 2) < 0) {
- free(&vlc->table);
- return; // Error
- }
-
- if(vlc->table_size != vlc->table_allocated)
- error("QDM2 needed %d had %d", vlc->table_size, vlc->table_allocated);
-}
-
-void QDM2Stream::softclipTableInit(void) {
- uint16 i;
- double dfl = SOFTCLIP_THRESHOLD - 32767;
- float delta = 1.0 / -dfl;
-
- for (i = 0; i < ARRAYSIZE(_softclipTable); i++)
- _softclipTable[i] = SOFTCLIP_THRESHOLD - ((int)(sin((float)i * delta) * dfl) & 0x0000FFFF);
-}
-
-// random generated table
-void QDM2Stream::rndTableInit(void) {
- uint16 i;
- uint16 j;
- uint32 ldw, hdw;
- // TODO: Replace Code with uint64 less version...
- int64_t tmp64_1;
- int64_t random_seed = 0;
- float delta = 1.0 / 16384.0;
-
- for(i = 0; i < ARRAYSIZE(_noiseTable); i++) {
- random_seed = random_seed * 214013 + 2531011;
- _noiseTable[i] = (delta * (float)(((int32)random_seed >> 16) & 0x00007FFF)- 1.0) * 1.3;
- }
-
- for (i = 0; i < 256; i++) {
- random_seed = 81;
- ldw = i;
- for (j = 0; j < 5; j++) {
- _randomDequantIndex[i][j] = (uint8)((ldw / random_seed) & 0xFF);
- ldw = (uint32)ldw % (uint32)random_seed;
- tmp64_1 = (random_seed * 0x55555556);
- hdw = (uint32)(tmp64_1 >> 32);
- random_seed = (int64_t)(hdw + (ldw >> 31));
- }
- }
-
- for (i = 0; i < 128; i++) {
- random_seed = 25;
- ldw = i;
- for (j = 0; j < 3; j++) {
- _randomDequantType24[i][j] = (uint8)((ldw / random_seed) & 0xFF);
- ldw = (uint32)ldw % (uint32)random_seed;
- tmp64_1 = (random_seed * 0x66666667);
- hdw = (uint32)(tmp64_1 >> 33);
- random_seed = hdw + (ldw >> 31);
- }
- }
-}
-
-void QDM2Stream::initNoiseSamples(void) {
- uint16 i;
- uint32 random_seed = 0;
- float delta = 1.0 / 16384.0;
-
- for (i = 0; i < ARRAYSIZE(_noiseSamples); i++) {
- random_seed = random_seed * 214013 + 2531011;
- _noiseSamples[i] = (delta * (float)((random_seed >> 16) & 0x00007fff) - 1.0);
- }
-}
-
-static const uint16 qdm2_vlc_offs[18] = {
- 0, 260, 566, 598, 894, 1166, 1230, 1294, 1678, 1950, 2214, 2278, 2310, 2570, 2834, 3124, 3448, 3838
-};
-
-void QDM2Stream::initVlc(void) {
- static int16 qdm2_table[3838][2];
-
- if (!_vlcsInitialized) {
- _vlcTabLevel.table = &qdm2_table[qdm2_vlc_offs[0]];
- _vlcTabLevel.table_allocated = qdm2_vlc_offs[1] - qdm2_vlc_offs[0];
- _vlcTabLevel.table_size = 0;
- initVlcSparse(&_vlcTabLevel, 8, 24,
- vlc_tab_level_huffbits, 1, 1,
- vlc_tab_level_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabDiff.table = &qdm2_table[qdm2_vlc_offs[1]];
- _vlcTabDiff.table_allocated = qdm2_vlc_offs[2] - qdm2_vlc_offs[1];
- _vlcTabDiff.table_size = 0;
- initVlcSparse(&_vlcTabDiff, 8, 37,
- vlc_tab_diff_huffbits, 1, 1,
- vlc_tab_diff_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabRun.table = &qdm2_table[qdm2_vlc_offs[2]];
- _vlcTabRun.table_allocated = qdm2_vlc_offs[3] - qdm2_vlc_offs[2];
- _vlcTabRun.table_size = 0;
- initVlcSparse(&_vlcTabRun, 5, 6,
- vlc_tab_run_huffbits, 1, 1,
- vlc_tab_run_huffcodes, 1, 1, NULL, 0, 0);
-
- _fftLevelExpAltVlc.table = &qdm2_table[qdm2_vlc_offs[3]];
- _fftLevelExpAltVlc.table_allocated = qdm2_vlc_offs[4] - qdm2_vlc_offs[3];
- _fftLevelExpAltVlc.table_size = 0;
- initVlcSparse(&_fftLevelExpAltVlc, 8, 28,
- fft_level_exp_alt_huffbits, 1, 1,
- fft_level_exp_alt_huffcodes, 2, 2, NULL, 0, 0);
-
- _fftLevelExpVlc.table = &qdm2_table[qdm2_vlc_offs[4]];
- _fftLevelExpVlc.table_allocated = qdm2_vlc_offs[5] - qdm2_vlc_offs[4];
- _fftLevelExpVlc.table_size = 0;
- initVlcSparse(&_fftLevelExpVlc, 8, 20,
- fft_level_exp_huffbits, 1, 1,
- fft_level_exp_huffcodes, 2, 2, NULL, 0, 0);
-
- _fftStereoExpVlc.table = &qdm2_table[qdm2_vlc_offs[5]];
- _fftStereoExpVlc.table_allocated = qdm2_vlc_offs[6] - qdm2_vlc_offs[5];
- _fftStereoExpVlc.table_size = 0;
- initVlcSparse(&_fftStereoExpVlc, 6, 7,
- fft_stereo_exp_huffbits, 1, 1,
- fft_stereo_exp_huffcodes, 1, 1, NULL, 0, 0);
-
- _fftStereoPhaseVlc.table = &qdm2_table[qdm2_vlc_offs[6]];
- _fftStereoPhaseVlc.table_allocated = qdm2_vlc_offs[7] - qdm2_vlc_offs[6];
- _fftStereoPhaseVlc.table_size = 0;
- initVlcSparse(&_fftStereoPhaseVlc, 6, 9,
- fft_stereo_phase_huffbits, 1, 1,
- fft_stereo_phase_huffcodes, 1, 1, NULL, 0, 0);
-
- _vlcTabToneLevelIdxHi1.table = &qdm2_table[qdm2_vlc_offs[7]];
- _vlcTabToneLevelIdxHi1.table_allocated = qdm2_vlc_offs[8] - qdm2_vlc_offs[7];
- _vlcTabToneLevelIdxHi1.table_size = 0;
- initVlcSparse(&_vlcTabToneLevelIdxHi1, 8, 20,
- vlc_tab_tone_level_idx_hi1_huffbits, 1, 1,
- vlc_tab_tone_level_idx_hi1_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabToneLevelIdxMid.table = &qdm2_table[qdm2_vlc_offs[8]];
- _vlcTabToneLevelIdxMid.table_allocated = qdm2_vlc_offs[9] - qdm2_vlc_offs[8];
- _vlcTabToneLevelIdxMid.table_size = 0;
- initVlcSparse(&_vlcTabToneLevelIdxMid, 8, 24,
- vlc_tab_tone_level_idx_mid_huffbits, 1, 1,
- vlc_tab_tone_level_idx_mid_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabToneLevelIdxHi2.table = &qdm2_table[qdm2_vlc_offs[9]];
- _vlcTabToneLevelIdxHi2.table_allocated = qdm2_vlc_offs[10] - qdm2_vlc_offs[9];
- _vlcTabToneLevelIdxHi2.table_size = 0;
- initVlcSparse(&_vlcTabToneLevelIdxHi2, 8, 24,
- vlc_tab_tone_level_idx_hi2_huffbits, 1, 1,
- vlc_tab_tone_level_idx_hi2_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabType30.table = &qdm2_table[qdm2_vlc_offs[10]];
- _vlcTabType30.table_allocated = qdm2_vlc_offs[11] - qdm2_vlc_offs[10];
- _vlcTabType30.table_size = 0;
- initVlcSparse(&_vlcTabType30, 6, 9,
- vlc_tab_type30_huffbits, 1, 1,
- vlc_tab_type30_huffcodes, 1, 1, NULL, 0, 0);
-
- _vlcTabType34.table = &qdm2_table[qdm2_vlc_offs[11]];
- _vlcTabType34.table_allocated = qdm2_vlc_offs[12] - qdm2_vlc_offs[11];
- _vlcTabType34.table_size = 0;
- initVlcSparse(&_vlcTabType34, 5, 10,
- vlc_tab_type34_huffbits, 1, 1,
- vlc_tab_type34_huffcodes, 1, 1, NULL, 0, 0);
-
- _vlcTabFftToneOffset[0].table = &qdm2_table[qdm2_vlc_offs[12]];
- _vlcTabFftToneOffset[0].table_allocated = qdm2_vlc_offs[13] - qdm2_vlc_offs[12];
- _vlcTabFftToneOffset[0].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[0], 8, 23,
- vlc_tab_fft_tone_offset_0_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_0_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabFftToneOffset[1].table = &qdm2_table[qdm2_vlc_offs[13]];
- _vlcTabFftToneOffset[1].table_allocated = qdm2_vlc_offs[14] - qdm2_vlc_offs[13];
- _vlcTabFftToneOffset[1].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[1], 8, 28,
- vlc_tab_fft_tone_offset_1_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_1_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabFftToneOffset[2].table = &qdm2_table[qdm2_vlc_offs[14]];
- _vlcTabFftToneOffset[2].table_allocated = qdm2_vlc_offs[15] - qdm2_vlc_offs[14];
- _vlcTabFftToneOffset[2].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[2], 8, 32,
- vlc_tab_fft_tone_offset_2_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_2_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabFftToneOffset[3].table = &qdm2_table[qdm2_vlc_offs[15]];
- _vlcTabFftToneOffset[3].table_allocated = qdm2_vlc_offs[16] - qdm2_vlc_offs[15];
- _vlcTabFftToneOffset[3].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[3], 8, 35,
- vlc_tab_fft_tone_offset_3_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_3_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcTabFftToneOffset[4].table = &qdm2_table[qdm2_vlc_offs[16]];
- _vlcTabFftToneOffset[4].table_allocated = qdm2_vlc_offs[17] - qdm2_vlc_offs[16];
- _vlcTabFftToneOffset[4].table_size = 0;
- initVlcSparse(&_vlcTabFftToneOffset[4], 8, 38,
- vlc_tab_fft_tone_offset_4_huffbits, 1, 1,
- vlc_tab_fft_tone_offset_4_huffcodes, 2, 2, NULL, 0, 0);
-
- _vlcsInitialized = true;
- }
-}
-
-QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) {
- uint32 tmp;
- int32 tmp_s;
- int tmp_val;
- int i;
-
- debug(1, "QDM2Stream::QDM2Stream() Call");
-
- _stream = stream;
- _compressedData = NULL;
- _subPacket = 0;
- memset(_quantizedCoeffs, 0, sizeof(_quantizedCoeffs));
- memset(_fftLevelExp, 0, sizeof(_fftLevelExp));
- _noiseIdx = 0;
- memset(_fftCoefsMinIndex, 0, sizeof(_fftCoefsMinIndex));
- memset(_fftCoefsMaxIndex, 0, sizeof(_fftCoefsMaxIndex));
- _fftToneStart = 0;
- _fftToneEnd = 0;
- for(i = 0; i < ARRAYSIZE(_subPacketListA); i++) {
- _subPacketListA[i].packet = NULL;
- _subPacketListA[i].next = NULL;
- }
- _subPacketsB = 0;
- for(i = 0; i < ARRAYSIZE(_subPacketListB); i++) {
- _subPacketListB[i].packet = NULL;
- _subPacketListB[i].next = NULL;
- }
- for(i = 0; i < ARRAYSIZE(_subPacketListC); i++) {
- _subPacketListC[i].packet = NULL;
- _subPacketListC[i].next = NULL;
- }
- for(i = 0; i < ARRAYSIZE(_subPacketListD); i++) {
- _subPacketListD[i].packet = NULL;
- _subPacketListD[i].next = NULL;
- }
- memset(_synthBuf, 0, sizeof(_synthBuf));
- memset(_synthBufOffset, 0, sizeof(_synthBufOffset));
- memset(_sbSamples, 0, sizeof(_sbSamples));
- memset(_outputBuffer, 0, sizeof(_outputBuffer));
- _vlcsInitialized = false;
- _superblocktype_2_3 = 0;
- _hasErrors = false;
-
- // Rewind extraData stream from any previous calls...
- extraData->seek(0, SEEK_SET);
-
- tmp_s = extraData->readSint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraSize: %d", tmp_s);
- if ((extraData->size() - extraData->pos()) / 4 + 1 != tmp_s)
- warning("QDM2Stream::QDM2Stream() extraSize mismatch - Expected %d", (extraData->size() - extraData->pos()) / 4 + 1);
- if (tmp_s < 12)
- error("QDM2Stream::QDM2Stream() Insufficient extraData");
-
- tmp = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraTag: %d", tmp);
- if (tmp != MKID_BE('frma'))
- warning("QDM2Stream::QDM2Stream() extraTag mismatch");
-
- tmp = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraType: %d", tmp);
- if (tmp == MKID_BE('QDMC'))
- warning("QDM2Stream::QDM2Stream() QDMC stream type not supported.");
- else if (tmp != MKID_BE('QDM2'))
- error("QDM2Stream::QDM2Stream() Unsupported stream type");
-
- tmp_s = extraData->readSint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraSize2: %d", tmp_s);
- if ((extraData->size() - extraData->pos()) + 4 != tmp_s)
- warning("QDM2Stream::QDM2Stream() extraSize2 mismatch - Expected %d", (extraData->size() - extraData->pos()) + 4);
-
- tmp = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraTag2: %d", tmp);
- if (tmp != MKID_BE('QDCA'))
- warning("QDM2Stream::QDM2Stream() extraTag2 mismatch");
-
- if (extraData->readUint32BE() != 1)
- warning("QDM2Stream::QDM2Stream() u0 field not 1");
-
- _channels = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() channels: %d", _channels);
-
- _sampleRate = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() sampleRate: %d", _sampleRate);
-
- _bitRate = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() bitRate: %d", _bitRate);
-
- _blockSize = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() blockSize: %d", _blockSize);
-
- _frameSize = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() frameSize: %d", _frameSize);
-
- _packetSize = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() packetSize: %d", _packetSize);
-
- if (extraData->size() - extraData->pos() != 0) {
- tmp_s = extraData->readSint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraSize3: %d", tmp_s);
- if (extraData->size() + 4 != tmp_s)
- warning("QDM2Stream::QDM2Stream() extraSize3 mismatch - Expected %d", extraData->size() + 4);
-
- tmp = extraData->readUint32BE();
- debug(1, "QDM2Stream::QDM2Stream() extraTag3: %d", tmp);
- if (tmp != MKID_BE('QDCP'))
- warning("QDM2Stream::QDM2Stream() extraTag3 mismatch");
-
- if ((float)extraData->readUint32BE() != 1.0)
- warning("QDM2Stream::QDM2Stream() uf0 field not 1.0");
-
- if (extraData->readUint32BE() != 0)
- warning("QDM2Stream::QDM2Stream() u1 field not 0");
-
- if ((float)extraData->readUint32BE() != 1.0)
- warning("QDM2Stream::QDM2Stream() uf1 field not 1.0");
-
- if ((float)extraData->readUint32BE() != 1.0)
- warning("QDM2Stream::QDM2Stream() uf2 field not 1.0");
-
- if (extraData->readUint32BE() != 27)
- warning("QDM2Stream::QDM2Stream() u2 field not 27");
-
- if (extraData->readUint32BE() != 8)
- warning("QDM2Stream::QDM2Stream() u3 field not 8");
-
- if (extraData->readUint32BE() != 0)
- warning("QDM2Stream::QDM2Stream() u4 field not 0");
- }
-
- _fftOrder = scummvm_log2(_frameSize) + 1;
- _fftFrameSize = 2 * _frameSize; // complex has two floats
-
- // something like max decodable tones
- _groupOrder = scummvm_log2(_blockSize) + 1;
- _sFrameSize = _blockSize / 16; // 16 iterations per super block
-
- _subSampling = _fftOrder - 7;
- _frequencyRange = 255 / (1 << (2 - _subSampling));
-
- switch ((_subSampling * 2 + _channels - 1)) {
- case 0:
- tmp = 40;
- break;
- case 1:
- tmp = 48;
- break;
- case 2:
- tmp = 56;
- break;
- case 3:
- tmp = 72;
- break;
- case 4:
- tmp = 80;
- break;
- case 5:
- tmp = 100;
- break;
- default:
- tmp = _subSampling;
- break;
- }
-
- tmp_val = 0;
- if ((tmp * 1000) < _bitRate) tmp_val = 1;
- if ((tmp * 1440) < _bitRate) tmp_val = 2;
- if ((tmp * 1760) < _bitRate) tmp_val = 3;
- if ((tmp * 2240) < _bitRate) tmp_val = 4;
- _cmTableSelect = tmp_val;
-
- if (_subSampling == 0)
- tmp = 7999;
- else
- tmp = ((-(_subSampling -1)) & 8000) + 20000;
-
- if (tmp < 8000)
- _coeffPerSbSelect = 0;
- else if (tmp <= 16000)
- _coeffPerSbSelect = 1;
- else
- _coeffPerSbSelect = 2;
-
- if (_fftOrder < 7 || _fftOrder > 9)
- error("QDM2Stream::QDM2Stream() Unsupported fft_order: %d", _fftOrder);
-
- rdftInit(&_rdftCtx, _fftOrder, IRDFT);
-
- initVlc();
- ff_mpa_synth_init(ff_mpa_synth_window);
- softclipTableInit();
- rndTableInit();
- initNoiseSamples();
-
- _compressedData = new uint8[_packetSize];
-}
-
-QDM2Stream::~QDM2Stream() {
- delete[] _compressedData;
- delete _stream;
-}
-
-static int qdm2_get_vlc(GetBitContext *gb, VLC *vlc, int flag, int depth) {
- int value = getVlc2(gb, vlc->table, vlc->bits, depth);
-
- // stage-2, 3 bits exponent escape sequence
- if (value-- == 0)
- value = getBits(gb, getBits (gb, 3) + 1);
-
- // stage-3, optional
- if (flag) {
- int tmp = vlc_stage3_values[value];
-
- if ((value & ~3) > 0)
- tmp += getBits(gb, (value >> 2));
- value = tmp;
- }
-
- return value;
-}
-
-static int qdm2_get_se_vlc(VLC *vlc, GetBitContext *gb, int depth)
-{
- int value = qdm2_get_vlc(gb, vlc, 0, depth);
-
- return (value & 1) ? ((value + 1) >> 1) : -(value >> 1);
-}
-
-/**
- * QDM2 checksum
- *
- * @param data pointer to data to be checksum'ed
- * @param length data length
- * @param value checksum value
- *
- * @return 0 if checksum is OK
- */
-static uint16 qdm2_packet_checksum(const uint8 *data, int length, int value) {
- int i;
-
- for (i = 0; i < length; i++)
- value -= data[i];
-
- return (uint16)(value & 0xffff);
-}
-
-/**
- * Fills a QDM2SubPacket structure with packet type, size, and data pointer.
- *
- * @param gb bitreader context
- * @param sub_packet packet under analysis
- */
-static void qdm2_decode_sub_packet_header(GetBitContext *gb, QDM2SubPacket *sub_packet)
-{
- sub_packet->type = getBits (gb, 8);
-
- if (sub_packet->type == 0) {
- sub_packet->size = 0;
- sub_packet->data = NULL;
- } else {
- sub_packet->size = getBits (gb, 8);
-
- if (sub_packet->type & 0x80) {
- sub_packet->size <<= 8;
- sub_packet->size |= getBits (gb, 8);
- sub_packet->type &= 0x7f;
- }
-
- if (sub_packet->type == 0x7f)
- sub_packet->type |= (getBits (gb, 8) << 8);
-
- sub_packet->data = &gb->buffer[getBitsCount(gb) / 8]; // FIXME: this depends on bitreader internal data
- }
-
- debug(1, "QDM2 Subpacket: type=%d size=%d start_offs=%x", sub_packet->type, sub_packet->size, getBitsCount(gb) / 8);
-}
-
-/**
- * Return node pointer to first packet of requested type in list.
- *
- * @param list list of subpackets to be scanned
- * @param type type of searched subpacket
- * @return node pointer for subpacket if found, else NULL
- */
-static QDM2SubPNode* qdm2_search_subpacket_type_in_list(QDM2SubPNode *list, int type)
-{
- while (list != NULL && list->packet != NULL) {
- if (list->packet->type == type)
- return list;
- list = list->next;
- }
- return NULL;
-}
-
-/**
- * Replaces 8 elements with their average value.
- * Called by qdm2_decode_superblock before starting subblock decoding.
- */
-void QDM2Stream::average_quantized_coeffs(void) {
- int i, j, n, ch, sum;
-
- n = coeff_per_sb_for_avg[_coeffPerSbSelect][QDM2_SB_USED(_subSampling) - 1] + 1;
-
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < n; i++) {
- sum = 0;
-
- for (j = 0; j < 8; j++)
- sum += _quantizedCoeffs[ch][i][j];
-
- sum /= 8;
- if (sum > 0)
- sum--;
-
- for (j = 0; j < 8; j++)
- _quantizedCoeffs[ch][i][j] = sum;
- }
- }
-}
-
-/**
- * Build subband samples with noise weighted by q->tone_level.
- * Called by synthfilt_build_sb_samples.
- *
- * @param sb subband index
- */
-void QDM2Stream::build_sb_samples_from_noise(int sb) {
- int ch, j;
-
- FIX_NOISE_IDX(_noiseIdx);
-
- if (!_channels)
- return;
-
- for (ch = 0; ch < _channels; ch++) {
- for (j = 0; j < 64; j++) {
- _sbSamples[ch][j * 2][sb] = (int32)(SB_DITHERING_NOISE(sb, _noiseIdx) * _toneLevel[ch][sb][j] + .5);
- _sbSamples[ch][j * 2 + 1][sb] = (int32)(SB_DITHERING_NOISE(sb, _noiseIdx) * _toneLevel[ch][sb][j] + .5);
- }
- }
-}
-
-/**
- * Called while processing data from subpackets 11 and 12.
- * Used after making changes to coding_method array.
- *
- * @param sb subband index
- * @param channels number of channels
- * @param coding_method q->coding_method[0][0][0]
- */
-void QDM2Stream::fix_coding_method_array(int sb, int channels, sb_int8_array coding_method)
-{
- int j, k;
- int ch;
- int run, case_val;
- int switchtable[23] = {0,5,1,5,5,5,5,5,2,5,5,5,5,5,5,5,3,5,5,5,5,5,4};
-
- for (ch = 0; ch < channels; ch++) {
- for (j = 0; j < 64; ) {
- if((coding_method[ch][sb][j] - 8) > 22) {
- run = 1;
- case_val = 8;
- } else {
- switch (switchtable[coding_method[ch][sb][j]-8]) {
- case 0: run = 10; case_val = 10; break;
- case 1: run = 1; case_val = 16; break;
- case 2: run = 5; case_val = 24; break;
- case 3: run = 3; case_val = 30; break;
- case 4: run = 1; case_val = 30; break;
- case 5: run = 1; case_val = 8; break;
- default: run = 1; case_val = 8; break;
- }
- }
- for (k = 0; k < run; k++)
- if (j + k < 128)
- if (coding_method[ch][sb + (j + k) / 64][(j + k) % 64] > coding_method[ch][sb][j])
- if (k > 0) {
- warning("QDM2 Untested Code: not debugged, almost never used");
- memset(&coding_method[ch][sb][j + k], case_val, k * sizeof(int8));
- memset(&coding_method[ch][sb][j + k], case_val, 3 * sizeof(int8));
- }
- j += run;
- }
- }
-}
-
-/**
- * Related to synthesis filter
- * Called by process_subpacket_10
- *
- * @param flag 1 if called after getting data from subpacket 10, 0 if no subpacket 10
- */
-void QDM2Stream::fill_tone_level_array(int flag) {
- int i, sb, ch, sb_used;
- int tmp, tab;
-
- // This should never happen
- if (_channels <= 0)
- return;
-
- for (ch = 0; ch < _channels; ch++) {
- for (sb = 0; sb < 30; sb++) {
- for (i = 0; i < 8; i++) {
- if ((tab=coeff_per_sb_for_dequant[_coeffPerSbSelect][sb]) < (last_coeff[_coeffPerSbSelect] - 1))
- tmp = _quantizedCoeffs[ch][tab + 1][i] * dequant_table[_coeffPerSbSelect][tab + 1][sb]+
- _quantizedCoeffs[ch][tab][i] * dequant_table[_coeffPerSbSelect][tab][sb];
- else
- tmp = _quantizedCoeffs[ch][tab][i] * dequant_table[_coeffPerSbSelect][tab][sb];
- if(tmp < 0)
- tmp += 0xff;
- _toneLevelIdxBase[ch][sb][i] = (tmp / 256) & 0xff;
- }
- }
- }
-
- sb_used = QDM2_SB_USED(_subSampling);
-
- if ((_superblocktype_2_3 != 0) && !flag) {
- for (sb = 0; sb < sb_used; sb++) {
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < 64; i++) {
- _toneLevelIdx[ch][sb][i] = _toneLevelIdxBase[ch][sb][i / 8];
- if (_toneLevelIdx[ch][sb][i] < 0)
- _toneLevel[ch][sb][i] = 0;
- else
- _toneLevel[ch][sb][i] = fft_tone_level_table[0][_toneLevelIdx[ch][sb][i] & 0x3f];
- }
- }
- }
- } else {
- tab = _superblocktype_2_3 ? 0 : 1;
- for (sb = 0; sb < sb_used; sb++) {
- if ((sb >= 4) && (sb <= 23)) {
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < 64; i++) {
- tmp = _toneLevelIdxBase[ch][sb][i / 8] -
- _toneLevelIdxHi1[ch][sb / 8][i / 8][i % 8] -
- _toneLevelIdxMid[ch][sb - 4][i / 8] -
- _toneLevelIdxHi2[ch][sb - 4];
- _toneLevelIdx[ch][sb][i] = tmp & 0xff;
- if ((tmp < 0) || (!_superblocktype_2_3 && !tmp))
- _toneLevel[ch][sb][i] = 0;
- else
- _toneLevel[ch][sb][i] = fft_tone_level_table[tab][tmp & 0x3f];
- }
- }
- } else {
- if (sb > 4) {
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < 64; i++) {
- tmp = _toneLevelIdxBase[ch][sb][i / 8] -
- _toneLevelIdxHi1[ch][2][i / 8][i % 8] -
- _toneLevelIdxHi2[ch][sb - 4];
- _toneLevelIdx[ch][sb][i] = tmp & 0xff;
- if ((tmp < 0) || (!_superblocktype_2_3 && !tmp))
- _toneLevel[ch][sb][i] = 0;
- else
- _toneLevel[ch][sb][i] = fft_tone_level_table[tab][tmp & 0x3f];
- }
- }
- } else {
- for (ch = 0; ch < _channels; ch++) {
- for (i = 0; i < 64; i++) {
- tmp = _toneLevelIdx[ch][sb][i] = _toneLevelIdxBase[ch][sb][i / 8];
- if ((tmp < 0) || (!_superblocktype_2_3 && !tmp))
- _toneLevel[ch][sb][i] = 0;
- else
- _toneLevel[ch][sb][i] = fft_tone_level_table[tab][tmp & 0x3f];
- }
- }
- }
- }
- }
- }
-}
-
-/**
- * Related to synthesis filter
- * Called by process_subpacket_11
- * c is built with data from subpacket 11
- * Most of this function is used only if superblock_type_2_3 == 0, never seen it in samples
- *
- * @param tone_level_idx
- * @param tone_level_idx_temp
- * @param coding_method q->coding_method[0][0][0]
- * @param nb_channels number of channels
- * @param c coming from subpacket 11, passed as 8*c
- * @param superblocktype_2_3 flag based on superblock packet type
- * @param cm_table_select q->cm_table_select
- */
-void QDM2Stream::fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp,
- sb_int8_array coding_method, int nb_channels,
- int c, int superblocktype_2_3, int cm_table_select) {
- int ch, sb, j;
- int tmp, acc, esp_40, comp;
- int add1, add2, add3, add4;
- // TODO : Remove multres 64 bit variable necessity...
- int64_t multres;
-
- // This should never happen
- if (nb_channels <= 0)
- return;
- if (!superblocktype_2_3) {
- warning("QDM2 This case is untested, no samples available");
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++) {
- for (j = 1; j < 63; j++) { // The loop only iterates to 63 so the code doesn't overflow the buffer
- add1 = tone_level_idx[ch][sb][j] - 10;
- if (add1 < 0)
- add1 = 0;
- add2 = add3 = add4 = 0;
- if (sb > 1) {
- add2 = tone_level_idx[ch][sb - 2][j] + tone_level_idx_offset_table[sb][0] - 6;
- if (add2 < 0)
- add2 = 0;
- }
- if (sb > 0) {
- add3 = tone_level_idx[ch][sb - 1][j] + tone_level_idx_offset_table[sb][1] - 6;
- if (add3 < 0)
- add3 = 0;
- }
- if (sb < 29) {
- add4 = tone_level_idx[ch][sb + 1][j] + tone_level_idx_offset_table[sb][3] - 6;
- if (add4 < 0)
- add4 = 0;
- }
- tmp = tone_level_idx[ch][sb][j + 1] * 2 - add4 - add3 - add2 - add1;
- if (tmp < 0)
- tmp = 0;
- tone_level_idx_temp[ch][sb][j + 1] = tmp & 0xff;
- }
- tone_level_idx_temp[ch][sb][0] = tone_level_idx_temp[ch][sb][1];
- }
- acc = 0;
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++)
- for (j = 0; j < 64; j++)
- acc += tone_level_idx_temp[ch][sb][j];
-
- multres = 0x66666667 * (acc * 10);
- esp_40 = (multres >> 32) / 8 + ((multres & 0xffffffff) >> 31);
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++)
- for (j = 0; j < 64; j++) {
- comp = tone_level_idx_temp[ch][sb][j]* esp_40 * 10;
- if (comp < 0)
- comp += 0xff;
- comp /= 256; // signed shift
- switch(sb) {
- case 0:
- if (comp < 30)
- comp = 30;
- comp += 15;
- break;
- case 1:
- if (comp < 24)
- comp = 24;
- comp += 10;
- break;
- case 2:
- case 3:
- case 4:
- if (comp < 16)
- comp = 16;
- }
- if (comp <= 5)
- tmp = 0;
- else if (comp <= 10)
- tmp = 10;
- else if (comp <= 16)
- tmp = 16;
- else if (comp <= 24)
- tmp = -1;
- else
- tmp = 0;
- coding_method[ch][sb][j] = ((tmp & 0xfffa) + 30 )& 0xff;
- }
- for (sb = 0; sb < 30; sb++)
- fix_coding_method_array(sb, nb_channels, coding_method);
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++)
- for (j = 0; j < 64; j++)
- if (sb >= 10) {
- if (coding_method[ch][sb][j] < 10)
- coding_method[ch][sb][j] = 10;
- } else {
- if (sb >= 2) {
- if (coding_method[ch][sb][j] < 16)
- coding_method[ch][sb][j] = 16;
- } else {
- if (coding_method[ch][sb][j] < 30)
- coding_method[ch][sb][j] = 30;
- }
- }
- } else { // superblocktype_2_3 != 0
- for (ch = 0; ch < nb_channels; ch++)
- for (sb = 0; sb < 30; sb++)
- for (j = 0; j < 64; j++)
- coding_method[ch][sb][j] = coding_method_table[cm_table_select][sb];
- }
-}
-
-/**
- *
- * Called by process_subpacket_11 to process more data from subpacket 11 with sb 0-8
- * Called by process_subpacket_12 to process data from subpacket 12 with sb 8-sb_used
- *
- * @param gb bitreader context
- * @param length packet length in bits
- * @param sb_min lower subband processed (sb_min included)
- * @param sb_max higher subband processed (sb_max excluded)
- */
-void QDM2Stream::synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max) {
- int sb, j, k, n, ch, run, channels;
- int joined_stereo, zero_encoding, chs;
- int type34_first;
- float type34_div = 0;
- float type34_predictor;
- float samples[10], sign_bits[16];
-
- if (length == 0) {
- // If no data use noise
- for (sb = sb_min; sb < sb_max; sb++)
- build_sb_samples_from_noise(sb);
-
- return;
- }
-
- for (sb = sb_min; sb < sb_max; sb++) {
- FIX_NOISE_IDX(_noiseIdx);
-
- channels = _channels;
-
- if (_channels <= 1 || sb < 12)
- joined_stereo = 0;
- else if (sb >= 24)
- joined_stereo = 1;
- else
- joined_stereo = (BITS_LEFT(length,gb) >= 1) ? getBits1 (gb) : 0;
-
- if (joined_stereo) {
- if (BITS_LEFT(length,gb) >= 16)
- for (j = 0; j < 16; j++)
- sign_bits[j] = getBits1(gb);
-
- for (j = 0; j < 64; j++)
- if (_codingMethod[1][sb][j] > _codingMethod[0][sb][j])
- _codingMethod[0][sb][j] = _codingMethod[1][sb][j];
-
- fix_coding_method_array(sb, _channels, _codingMethod);
- channels = 1;
- }
-
- for (ch = 0; ch < channels; ch++) {
- zero_encoding = (BITS_LEFT(length,gb) >= 1) ? getBits1(gb) : 0;
- type34_predictor = 0.0;
- type34_first = 1;
-
- for (j = 0; j < 128; ) {
- switch (_codingMethod[ch][sb][j / 2]) {
- case 8:
- if (BITS_LEFT(length,gb) >= 10) {
- if (zero_encoding) {
- for (k = 0; k < 5; k++) {
- if ((j + 2 * k) >= 128)
- break;
- samples[2 * k] = getBits1(gb) ? dequant_1bit[joined_stereo][2 * getBits1(gb)] : 0;
- }
- } else {
- n = getBits(gb, 8);
- for (k = 0; k < 5; k++)
- samples[2 * k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]];
- }
- for (k = 0; k < 5; k++)
- samples[2 * k + 1] = SB_DITHERING_NOISE(sb, _noiseIdx);
- } else {
- for (k = 0; k < 10; k++)
- samples[k] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 10;
- break;
-
- case 10:
- if (BITS_LEFT(length,gb) >= 1) {
- double f = 0.81;
-
- if (getBits1(gb))
- f = -f;
- f -= _noiseSamples[((sb + 1) * (j +5 * ch + 1)) & 127] * 9.0 / 40.0;
- samples[0] = f;
- } else {
- samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 1;
- break;
-
- case 16:
- if (BITS_LEFT(length,gb) >= 10) {
- if (zero_encoding) {
- for (k = 0; k < 5; k++) {
- if ((j + k) >= 128)
- break;
- samples[k] = (getBits1(gb) == 0) ? 0 : dequant_1bit[joined_stereo][2 * getBits1(gb)];
- }
- } else {
- n = getBits (gb, 8);
- for (k = 0; k < 5; k++)
- samples[k] = dequant_1bit[joined_stereo][_randomDequantIndex[n][k]];
- }
- } else {
- for (k = 0; k < 5; k++)
- samples[k] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 5;
- break;
-
- case 24:
- if (BITS_LEFT(length,gb) >= 7) {
- n = getBits(gb, 7);
- for (k = 0; k < 3; k++)
- samples[k] = (_randomDequantType24[n][k] - 2.0) * 0.5;
- } else {
- for (k = 0; k < 3; k++)
- samples[k] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 3;
- break;
-
- case 30:
- if (BITS_LEFT(length,gb) >= 4)
- samples[0] = type30_dequant[qdm2_get_vlc(gb, &_vlcTabType30, 0, 1)];
- else
- samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
-
- run = 1;
- break;
-
- case 34:
- if (BITS_LEFT(length,gb) >= 7) {
- if (type34_first) {
- type34_div = (float)(1 << getBits(gb, 2));
- samples[0] = ((float)getBits(gb, 5) - 16.0) / 15.0;
- type34_predictor = samples[0];
- type34_first = 0;
- } else {
- samples[0] = type34_delta[qdm2_get_vlc(gb, &_vlcTabType34, 0, 1)] / type34_div + type34_predictor;
- type34_predictor = samples[0];
- }
- } else {
- samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
- }
- run = 1;
- break;
-
- default:
- samples[0] = SB_DITHERING_NOISE(sb, _noiseIdx);
- run = 1;
- break;
- }
-
- if (joined_stereo) {
- float tmp[10][MPA_MAX_CHANNELS];
-
- for (k = 0; k < run; k++) {
- tmp[k][0] = samples[k];
- tmp[k][1] = (sign_bits[(j + k) / 8]) ? -samples[k] : samples[k];
- }
- for (chs = 0; chs < _channels; chs++)
- for (k = 0; k < run; k++)
- if ((j + k) < 128)
- _sbSamples[chs][j + k][sb] = (int32)(_toneLevel[chs][sb][((j + k)/2)] * tmp[k][chs] + .5);
- } else {
- for (k = 0; k < run; k++)
- if ((j + k) < 128)
- _sbSamples[ch][j + k][sb] = (int32)(_toneLevel[ch][sb][(j + k)/2] * samples[k] + .5);
- }
-
- j += run;
- } // j loop
- } // channel loop
- } // subband loop
-}
-
-/**
- * Init the first element of a channel in quantized_coeffs with data from packet 10 (quantized_coeffs[ch][0]).
- * This is similar to process_subpacket_9, but for a single channel and for element [0]
- * same VLC tables as process_subpacket_9 are used.
- *
- * @param quantized_coeffs pointer to quantized_coeffs[ch][0]
- * @param gb bitreader context
- * @param length packet length in bits
- */
-void QDM2Stream::init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length) {
- int i, k, run, level, diff;
-
- if (BITS_LEFT(length,gb) < 16)
- return;
- level = qdm2_get_vlc(gb, &_vlcTabLevel, 0, 2);
-
- quantized_coeffs[0] = level;
-
- for (i = 0; i < 7; ) {
- if (BITS_LEFT(length,gb) < 16)
- break;
- run = qdm2_get_vlc(gb, &_vlcTabRun, 0, 1) + 1;
-
- if (BITS_LEFT(length,gb) < 16)
- break;
- diff = qdm2_get_se_vlc(&_vlcTabDiff, gb, 2);
-
- for (k = 1; k <= run; k++)
- quantized_coeffs[i + k] = (level + ((k * diff) / run));
-
- level += diff;
- i += run;
- }
-}
-
-/**
- * Related to synthesis filter, process data from packet 10
- * Init part of quantized_coeffs via function init_quantized_coeffs_elem0
- * Init tone_level_idx_hi1, tone_level_idx_hi2, tone_level_idx_mid with data from packet 10
- *
- * @param gb bitreader context
- * @param length packet length in bits
- */
-void QDM2Stream::init_tone_level_dequantization(GetBitContext *gb, int length) {
- int sb, j, k, n, ch;
-
- for (ch = 0; ch < _channels; ch++) {
- init_quantized_coeffs_elem0(_quantizedCoeffs[ch][0], gb, length);
-
- if (BITS_LEFT(length,gb) < 16) {
- memset(_quantizedCoeffs[ch][0], 0, 8);
- break;
- }
- }
-
- n = _subSampling + 1;
-
- for (sb = 0; sb < n; sb++)
- for (ch = 0; ch < _channels; ch++)
- for (j = 0; j < 8; j++) {
- if (BITS_LEFT(length,gb) < 1)
- break;
- if (getBits1(gb)) {
- for (k=0; k < 8; k++) {
- if (BITS_LEFT(length,gb) < 16)
- break;
- _toneLevelIdxHi1[ch][sb][j][k] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxHi1, 0, 2);
- }
- } else {
- for (k=0; k < 8; k++)
- _toneLevelIdxHi1[ch][sb][j][k] = 0;
- }
- }
-
- n = QDM2_SB_USED(_subSampling) - 4;
-
- for (sb = 0; sb < n; sb++)
- for (ch = 0; ch < _channels; ch++) {
- if (BITS_LEFT(length,gb) < 16)
- break;
- _toneLevelIdxHi2[ch][sb] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxHi2, 0, 2);
- if (sb > 19)
- _toneLevelIdxHi2[ch][sb] -= 16;
- else
- for (j = 0; j < 8; j++)
- _toneLevelIdxMid[ch][sb][j] = -16;
- }
-
- n = QDM2_SB_USED(_subSampling) - 5;
-
- for (sb = 0; sb < n; sb++) {
- for (ch = 0; ch < _channels; ch++) {
- for (j = 0; j < 8; j++) {
- if (BITS_LEFT(length,gb) < 16)
- break;
- _toneLevelIdxMid[ch][sb][j] = qdm2_get_vlc(gb, &_vlcTabToneLevelIdxMid, 0, 2) - 32;
- }
- }
- }
-}
-
-/**
- * Process subpacket 9, init quantized_coeffs with data from it
- *
- * @param node pointer to node with packet
- */
-void QDM2Stream::process_subpacket_9(QDM2SubPNode *node) {
- GetBitContext gb;
- int i, j, k, n, ch, run, level, diff;
-
- initGetBits(&gb, node->packet->data, node->packet->size*8);
-
- n = coeff_per_sb_for_avg[_coeffPerSbSelect][QDM2_SB_USED(_subSampling) - 1] + 1; // same as averagesomething function
-
- for (i = 1; i < n; i++)
- for (ch = 0; ch < _channels; ch++) {
- level = qdm2_get_vlc(&gb, &_vlcTabLevel, 0, 2);
- _quantizedCoeffs[ch][i][0] = level;
-
- for (j = 0; j < (8 - 1); ) {
- run = qdm2_get_vlc(&gb, &_vlcTabRun, 0, 1) + 1;
- diff = qdm2_get_se_vlc(&_vlcTabDiff, &gb, 2);
-
- for (k = 1; k <= run; k++)
- _quantizedCoeffs[ch][i][j + k] = (level + ((k*diff) / run));
-
- level += diff;
- j += run;
- }
- }
-
- for (ch = 0; ch < _channels; ch++)
- for (i = 0; i < 8; i++)
- _quantizedCoeffs[ch][0][i] = 0;
-}
-
-/**
- * Process subpacket 10 if not null, else
- *
- * @param node pointer to node with packet
- * @param length packet length in bits
- */
-void QDM2Stream::process_subpacket_10(QDM2SubPNode *node, int length) {
- GetBitContext gb;
-
- initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
-
- if (length != 0) {
- init_tone_level_dequantization(&gb, length);
- fill_tone_level_array(1);
- } else {
- fill_tone_level_array(0);
- }
-}
-
-/**
- * Process subpacket 11
- *
- * @param node pointer to node with packet
- * @param length packet length in bit
- */
-void QDM2Stream::process_subpacket_11(QDM2SubPNode *node, int length) {
- GetBitContext gb;
-
- initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
- if (length >= 32) {
- int c = getBits (&gb, 13);
-
- if (c > 3)
- fill_coding_method_array(_toneLevelIdx, _toneLevelIdxTemp, _codingMethod,
- _channels, 8*c, _superblocktype_2_3, _cmTableSelect);
- }
-
- synthfilt_build_sb_samples(&gb, length, 0, 8);
-}
-
-/**
- * Process subpacket 12
- *
- * @param node pointer to node with packet
- * @param length packet length in bits
- */
-void QDM2Stream::process_subpacket_12(QDM2SubPNode *node, int length) {
- GetBitContext gb;
-
- initGetBits(&gb, ((node == NULL) ? _emptyBuffer : node->packet->data), ((node == NULL) ? 0 : node->packet->size*8));
- synthfilt_build_sb_samples(&gb, length, 8, QDM2_SB_USED(_subSampling));
-}
-
-/*
- * Process new subpackets for synthesis filter
- *
- * @param list list with synthesis filter packets (list D)
- */
-void QDM2Stream::process_synthesis_subpackets(QDM2SubPNode *list) {
- struct QDM2SubPNode *nodes[4];
-
- nodes[0] = qdm2_search_subpacket_type_in_list(list, 9);
- if (nodes[0] != NULL)
- process_subpacket_9(nodes[0]);
-
- nodes[1] = qdm2_search_subpacket_type_in_list(list, 10);
- if (nodes[1] != NULL)
- process_subpacket_10(nodes[1], nodes[1]->packet->size << 3);
- else
- process_subpacket_10(NULL, 0);
-
- nodes[2] = qdm2_search_subpacket_type_in_list(list, 11);
- if (nodes[0] != NULL && nodes[1] != NULL && nodes[2] != NULL)
- process_subpacket_11(nodes[2], (nodes[2]->packet->size << 3));
- else
- process_subpacket_11(NULL, 0);
-
- nodes[3] = qdm2_search_subpacket_type_in_list(list, 12);
- if (nodes[0] != NULL && nodes[1] != NULL && nodes[3] != NULL)
- process_subpacket_12(nodes[3], (nodes[3]->packet->size << 3));
- else
- process_subpacket_12(NULL, 0);
-}
-
-/*
- * Decode superblock, fill packet lists.
- *
- */
-void QDM2Stream::qdm2_decode_super_block(void) {
- GetBitContext gb;
- struct QDM2SubPacket header, *packet;
- int i, packet_bytes, sub_packet_size, subPacketsD;
- unsigned int next_index = 0;
-
- memset(_toneLevelIdxHi1, 0, sizeof(_toneLevelIdxHi1));
- memset(_toneLevelIdxMid, 0, sizeof(_toneLevelIdxMid));
- memset(_toneLevelIdxHi2, 0, sizeof(_toneLevelIdxHi2));
-
- _subPacketsB = 0;
- subPacketsD = 0;
-
- average_quantized_coeffs(); // average elements in quantized_coeffs[max_ch][10][8]
-
- initGetBits(&gb, _compressedData, _packetSize*8);
- qdm2_decode_sub_packet_header(&gb, &header);
-
- if (header.type < 2 || header.type >= 8) {
- _hasErrors = true;
- error("QDM2 : bad superblock type");
- return;
- }
-
- _superblocktype_2_3 = (header.type == 2 || header.type == 3);
- packet_bytes = (_packetSize - getBitsCount(&gb) / 8);
-
- initGetBits(&gb, header.data, header.size*8);
-
- if (header.type == 2 || header.type == 4 || header.type == 5) {
- int csum = 257 * getBits(&gb, 8) + 2 * getBits(&gb, 8);
-
- csum = qdm2_packet_checksum(_compressedData, _packetSize, csum);
-
- if (csum != 0) {
- _hasErrors = true;
- error("QDM2 : bad packet checksum");
- return;
- }
- }
-
- _subPacketListB[0].packet = NULL;
- _subPacketListD[0].packet = NULL;
-
- for (i = 0; i < 6; i++)
- if (--_fftLevelExp[i] < 0)
- _fftLevelExp[i] = 0;
-
- for (i = 0; packet_bytes > 0; i++) {
- int j;
-
- _subPacketListA[i].next = NULL;
-
- if (i > 0) {
- _subPacketListA[i - 1].next = &_subPacketListA[i];
-
- // seek to next block
- initGetBits(&gb, header.data, header.size*8);
- skipBits(&gb, next_index*8);
-
- if (next_index >= header.size)
- break;
- }
-
- // decode subpacket
- packet = &_subPackets[i];
- qdm2_decode_sub_packet_header(&gb, packet);
- next_index = packet->size + getBitsCount(&gb) / 8;
- sub_packet_size = ((packet->size > 0xff) ? 1 : 0) + packet->size + 2;
-
- if (packet->type == 0)
- break;
-
- if (sub_packet_size > packet_bytes) {
- if (packet->type != 10 && packet->type != 11 && packet->type != 12)
- break;
- packet->size += packet_bytes - sub_packet_size;
- }
-
- packet_bytes -= sub_packet_size;
-
- // add subpacket to 'all subpackets' list
- _subPacketListA[i].packet = packet;
-
- // add subpacket to related list
- if (packet->type == 8) {
- error("Unsupported packet type 8");
- return;
- } else if (packet->type >= 9 && packet->type <= 12) {
- // packets for MPEG Audio like Synthesis Filter
- QDM2_LIST_ADD(_subPacketListD, subPacketsD, packet);
- } else if (packet->type == 13) {
- for (j = 0; j < 6; j++)
- _fftLevelExp[j] = getBits(&gb, 6);
- } else if (packet->type == 14) {
- for (j = 0; j < 6; j++)
- _fftLevelExp[j] = qdm2_get_vlc(&gb, &_fftLevelExpVlc, 0, 2);
- } else if (packet->type == 15) {
- error("Unsupported packet type 15");
- return;
- } else if (packet->type >= 16 && packet->type < 48 && !fft_subpackets[packet->type - 16]) {
- // packets for FFT
- QDM2_LIST_ADD(_subPacketListB, _subPacketsB, packet);
- }
- } // Packet bytes loop
-
-// ****************************************************************
- if (_subPacketListD[0].packet != NULL) {
- process_synthesis_subpackets(_subPacketListD);
- _doSynthFilter = 1;
- } else if (_doSynthFilter) {
- process_subpacket_10(NULL, 0);
- process_subpacket_11(NULL, 0);
- process_subpacket_12(NULL, 0);
- }
-// ****************************************************************
-}
-
-void QDM2Stream::qdm2_fft_init_coefficient(int sub_packet, int offset, int duration,
- int channel, int exp, int phase) {
- if (_fftCoefsMinIndex[duration] < 0)
- _fftCoefsMinIndex[duration] = _fftCoefsIndex;
-
- _fftCoefs[_fftCoefsIndex].sub_packet = ((sub_packet >= 16) ? (sub_packet - 16) : sub_packet);
- _fftCoefs[_fftCoefsIndex].channel = channel;
- _fftCoefs[_fftCoefsIndex].offset = offset;
- _fftCoefs[_fftCoefsIndex].exp = exp;
- _fftCoefs[_fftCoefsIndex].phase = phase;
- _fftCoefsIndex++;
-}
-
-void QDM2Stream::qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b) {
- debug(1, "QDM2Stream::qdm2_fft_decode_tones() duration: %d b:%d", duration, b);
- int channel, stereo, phase, exp;
- int local_int_4, local_int_8, stereo_phase, local_int_10;
- int local_int_14, stereo_exp, local_int_20, local_int_28;
- int n, offset;
-
- local_int_4 = 0;
- local_int_28 = 0;
- local_int_20 = 2;
- local_int_8 = (4 - duration);
- local_int_10 = 1 << (_groupOrder - duration - 1);
- offset = 1;
-
- while (1) {
- if (_superblocktype_2_3) {
- debug(1, "QDM2Stream::qdm2_fft_decode_tones() local_int_8: %d", local_int_8);
- while ((n = qdm2_get_vlc(gb, &_vlcTabFftToneOffset[local_int_8], 1, 2)) < 2) {
- debug(1, "QDM2Stream::qdm2_fft_decode_tones() local_int_8: %d", local_int_8);
- offset = 1;
- if (n == 0) {
- local_int_4 += local_int_10;
- local_int_28 += (1 << local_int_8);
- } else {
- local_int_4 += 8*local_int_10;
- local_int_28 += (8 << local_int_8);
- }
- }
- offset += (n - 2);
- } else {
- offset += qdm2_get_vlc(gb, &_vlcTabFftToneOffset[local_int_8], 1, 2);
- while (offset >= (local_int_10 - 1)) {
- offset += (1 - (local_int_10 - 1));
- local_int_4 += local_int_10;
- local_int_28 += (1 << local_int_8);
- }
- }
-
- if (local_int_4 >= _blockSize)
- return;
-
- local_int_14 = (offset >> local_int_8);
-
- if (_channels > 1) {
- channel = getBits1(gb);
- stereo = getBits1(gb);
- } else {
- channel = 0;
- stereo = 0;
- }
-
- exp = qdm2_get_vlc(gb, (b ? &_fftLevelExpVlc : &_fftLevelExpAltVlc), 0, 2);
- exp += _fftLevelExp[fft_level_index_table[local_int_14]];
- exp = (exp < 0) ? 0 : exp;
-
- phase = getBits(gb, 3);
- stereo_exp = 0;
- stereo_phase = 0;
-
- if (stereo) {
- stereo_exp = (exp - qdm2_get_vlc(gb, &_fftStereoExpVlc, 0, 1));
- stereo_phase = (phase - qdm2_get_vlc(gb, &_fftStereoPhaseVlc, 0, 1));
- if (stereo_phase < 0)
- stereo_phase += 8;
- }
-
- if (_frequencyRange > (local_int_14 + 1)) {
- int sub_packet = (local_int_20 + local_int_28);
-
- qdm2_fft_init_coefficient(sub_packet, offset, duration, channel, exp, phase);
- if (stereo)
- qdm2_fft_init_coefficient(sub_packet, offset, duration, (1 - channel), stereo_exp, stereo_phase);
- }
-
- offset++;
- }
-}
-
-void QDM2Stream::qdm2_decode_fft_packets(void) {
- debug(1, "QDM2Stream::qdm2_decode_fft_packets()");
- int i, j, min, max, value, type, unknown_flag;
- GetBitContext gb;
-
- if (_subPacketListB[0].packet == NULL)
- return;
-
- // reset minimum indexes for FFT coefficients
- _fftCoefsIndex = 0;
- for (i=0; i < 5; i++)
- _fftCoefsMinIndex[i] = -1;
-
- // process subpackets ordered by type, largest type first
- for (i = 0, max = 256; i < _subPacketsB; i++) {
- QDM2SubPacket *packet= NULL;
-
- // find subpacket with largest type less than max
- for (j = 0, min = 0; j < _subPacketsB; j++) {
- value = _subPacketListB[j].packet->type;
- if (value > min && value < max) {
- min = value;
- packet = _subPacketListB[j].packet;
- }
- }
-
- max = min;
-
- // check for errors (?)
- if (!packet)
- return;
-
- if (i == 0 && (packet->type < 16 || packet->type >= 48 || fft_subpackets[packet->type - 16]))
- return;
-
- // decode FFT tones
- debug(1, "QDM2Stream::qdm2_decode_fft_packets initGetBits() packet->size*8: %d", packet->size*8);
- initGetBits(&gb, packet->data, packet->size*8);
-
- if (packet->type >= 32 && packet->type < 48 && !fft_subpackets[packet->type - 16])
- unknown_flag = 1;
- else
- unknown_flag = 0;
-
- type = packet->type;
-
- if ((type >= 17 && type < 24) || (type >= 33 && type < 40)) {
- int duration = _subSampling + 5 - (type & 15);
-
- if (duration >= 0 && duration < 4) { // TODO: Should be <= 4?
- debug(1, "QDM2Stream::qdm2_decode_fft_packets qdm2_fft_decode_tones() #1");
- qdm2_fft_decode_tones(duration, &gb, unknown_flag);
- }
- } else if (type == 31) {
- for (j=0; j < 4; j++) {
- debug(1, "QDM2Stream::qdm2_decode_fft_packets qdm2_fft_decode_tones() #2");
- qdm2_fft_decode_tones(j, &gb, unknown_flag);
- }
- } else if (type == 46) {
- for (j=0; j < 6; j++)
- _fftLevelExp[j] = getBits(&gb, 6);
- for (j=0; j < 4; j++) {
- debug(1, "QDM2Stream::qdm2_decode_fft_packets qdm2_fft_decode_tones() #3");
- qdm2_fft_decode_tones(j, &gb, unknown_flag);
- }
- }
- } // Loop on B packets
-
- // calculate maximum indexes for FFT coefficients
- for (i = 0, j = -1; i < 5; i++)
- if (_fftCoefsMinIndex[i] >= 0) {
- if (j >= 0)
- _fftCoefsMaxIndex[j] = _fftCoefsMinIndex[i];
- j = i;
- }
- if (j >= 0)
- _fftCoefsMaxIndex[j] = _fftCoefsIndex;
-}
-
-void QDM2Stream::qdm2_fft_generate_tone(FFTTone *tone)
-{
- float level, f[6];
- int i;
- QDM2Complex c;
- const double iscale = 2.0 * PI / 512.0;
-
- tone->phase += tone->phase_shift;
-
- // calculate current level (maximum amplitude) of tone
- level = fft_tone_envelope_table[tone->duration][tone->time_index] * tone->level;
- c.im = level * sin(tone->phase*iscale);
- c.re = level * cos(tone->phase*iscale);
-
- // generate FFT coefficients for tone
- if (tone->duration >= 3 || tone->cutoff >= 3) {
- tone->complex[0].im += c.im;
- tone->complex[0].re += c.re;
- tone->complex[1].im -= c.im;
- tone->complex[1].re -= c.re;
- } else {
- f[1] = -tone->table[4];
- f[0] = tone->table[3] - tone->table[0];
- f[2] = 1.0 - tone->table[2] - tone->table[3];
- f[3] = tone->table[1] + tone->table[4] - 1.0;
- f[4] = tone->table[0] - tone->table[1];
- f[5] = tone->table[2];
- for (i = 0; i < 2; i++) {
- tone->complex[fft_cutoff_index_table[tone->cutoff][i]].re += c.re * f[i];
- tone->complex[fft_cutoff_index_table[tone->cutoff][i]].im += c.im *((tone->cutoff <= i) ? -f[i] : f[i]);
- }
- for (i = 0; i < 4; i++) {
- tone->complex[i].re += c.re * f[i+2];
- tone->complex[i].im += c.im * f[i+2];
- }
- }
-
- // copy the tone if it has not yet died out
- if (++tone->time_index < ((1 << (5 - tone->duration)) - 1)) {
- memcpy(&_fftTones[_fftToneEnd], tone, sizeof(FFTTone));
- _fftToneEnd = (_fftToneEnd + 1) % 1000;
- }
-}
-
-void QDM2Stream::qdm2_fft_tone_synthesizer(uint8 sub_packet) {
- int i, j, ch;
- const double iscale = 0.25 * PI;
-
- for (ch = 0; ch < _channels; ch++) {
- memset(_fft.complex[ch], 0, _frameSize * sizeof(QDM2Complex));
- }
-
- // apply FFT tones with duration 4 (1 FFT period)
- if (_fftCoefsMinIndex[4] >= 0)
- for (i = _fftCoefsMinIndex[4]; i < _fftCoefsMaxIndex[4]; i++) {
- float level;
- QDM2Complex c;
-
- if (_fftCoefs[i].sub_packet != sub_packet)
- break;
-
- ch = (_channels == 1) ? 0 : _fftCoefs[i].channel;
- level = (_fftCoefs[i].exp < 0) ? 0.0 : fft_tone_level_table[_superblocktype_2_3 ? 0 : 1][_fftCoefs[i].exp & 63];
-
- c.re = level * cos(_fftCoefs[i].phase * iscale);
- c.im = level * sin(_fftCoefs[i].phase * iscale);
- _fft.complex[ch][_fftCoefs[i].offset + 0].re += c.re;
- _fft.complex[ch][_fftCoefs[i].offset + 0].im += c.im;
- _fft.complex[ch][_fftCoefs[i].offset + 1].re -= c.re;
- _fft.complex[ch][_fftCoefs[i].offset + 1].im -= c.im;
- }
-
- // generate existing FFT tones
- for (i = _fftToneEnd; i != _fftToneStart; ) {
- qdm2_fft_generate_tone(&_fftTones[_fftToneStart]);
- _fftToneStart = (_fftToneStart + 1) % 1000;
- }
-
- // create and generate new FFT tones with duration 0 (long) to 3 (short)
- for (i = 0; i < 4; i++)
- if (_fftCoefsMinIndex[i] >= 0) {
- for (j = _fftCoefsMinIndex[i]; j < _fftCoefsMaxIndex[i]; j++) {
- int offset, four_i;
- FFTTone tone;
-
- if (_fftCoefs[j].sub_packet != sub_packet)
- break;
-
- four_i = (4 - i);
- offset = _fftCoefs[j].offset >> four_i;
- ch = (_channels == 1) ? 0 : _fftCoefs[j].channel;
-
- if (offset < _frequencyRange) {
- if (offset < 2)
- tone.cutoff = offset;
- else
- tone.cutoff = (offset >= 60) ? 3 : 2;
-
- tone.level = (_fftCoefs[j].exp < 0) ? 0.0 : fft_tone_level_table[_superblocktype_2_3 ? 0 : 1][_fftCoefs[j].exp & 63];
- tone.complex = &_fft.complex[ch][offset];
- tone.table = fft_tone_sample_table[i][_fftCoefs[j].offset - (offset << four_i)];
- tone.phase = 64 * _fftCoefs[j].phase - (offset << 8) - 128;
- tone.phase_shift = (2 * _fftCoefs[j].offset + 1) << (7 - four_i);
- tone.duration = i;
- tone.time_index = 0;
-
- qdm2_fft_generate_tone(&tone);
- }
- }
- _fftCoefsMinIndex[i] = j;
- }
-}
-
-void QDM2Stream::qdm2_calculate_fft(int channel) {
- debug(1, "QDM2Stream::qdm2_calculate_fft channel: %d", channel);
- const float gain = (_channels == 1 && _channels == 2) ? 0.5f : 1.0f;
- int i;
-
- _fft.complex[channel][0].re *= 2.0f;
- _fft.complex[channel][0].im = 0.0f;
-
- //debug(1, "QDM2Stream::qdm2_calculate_fft _fft.complex[channel][0].re: %lf", _fft.complex[channel][0].re);
- //debug(1, "QDM2Stream::qdm2_calculate_fft _fft.complex[channel][0].im: %lf", _fft.complex[channel][0].im);
-
- rdftCalc(&_rdftCtx, (float *)_fft.complex[channel]);
-
- // add samples to output buffer
- for (i = 0; i < ((_fftFrameSize + 15) & ~15); i++)
- _outputBuffer[_channels * i + channel] += ((float *) _fft.complex[channel])[i] * gain;
-}
-
-/**
- * @param index subpacket number
- */
-void QDM2Stream::qdm2_synthesis_filter(uint8 index)
-{
- int16 samples[MPA_MAX_CHANNELS * MPA_FRAME_SIZE];
- int i, k, ch, sb_used, sub_sampling, dither_state = 0;
-
- // copy sb_samples
- sb_used = QDM2_SB_USED(_subSampling);
-
- for (ch = 0; ch < _channels; ch++)
- for (i = 0; i < 8; i++)
- for (k = sb_used; k < 32; k++)
- _sbSamples[ch][(8 * index) + i][k] = 0;
-
- for (ch = 0; ch < _channels; ch++) {
- int16 *samples_ptr = samples + ch;
-
- for (i = 0; i < 8; i++) {
- ff_mpa_synth_filter(_synthBuf[ch], &(_synthBufOffset[ch]),
- ff_mpa_synth_window, &dither_state,
- samples_ptr, _channels,
- _sbSamples[ch][(8 * index) + i]);
- samples_ptr += 32 * _channels;
- }
- }
-
- // add samples to output buffer
- sub_sampling = (4 >> _subSampling);
-
- for (ch = 0; ch < _channels; ch++)
- for (i = 0; i < _sFrameSize; i++)
- _outputBuffer[_channels * i + ch] += (float)(samples[_channels * sub_sampling * i + ch] >> (sizeof(int16)*8-16));
-}
-
-int QDM2Stream::qdm2_decodeFrame(Common::SeekableReadStream *in) {
- debug(1, "QDM2Stream::qdm2_decodeFrame in->pos(): %d in->size(): %d", in->pos(), in->size());
- int ch, i;
- const int frame_size = (_sFrameSize * _channels);
-
- // select input buffer
- if(in->eos() || in->size() == in->pos()) {
- debug(1, "QDM2Stream::qdm2_decodeFrame End of Input Stream");
- return 0;
- }
- if((in->size() - in->pos()) < _packetSize) {
- debug(1, "QDM2Stream::qdm2_decodeFrame Insufficient Packet Data in Input Stream Found: %d Need: %d", in->size() - in->pos(), _packetSize);
- return 0;
- }
-
- in->read(_compressedData, _packetSize);
- debug(1, "QDM2Stream::qdm2_decodeFrame constructed input data");
-
- // copy old block, clear new block of output samples
- memmove(_outputBuffer, &_outputBuffer[frame_size], frame_size * sizeof(float));
- memset(&_outputBuffer[frame_size], 0, frame_size * sizeof(float));
- debug(1, "QDM2Stream::qdm2_decodeFrame cleared outputBuffer");
-
- // decode block of QDM2 compressed data
- debug(1, "QDM2Stream::qdm2_decodeFrame decode block of QDM2 compressed data");
- if (_subPacket == 0) {
- _hasErrors = false; // reset it for a new super block
- debug(1, "QDM2 : Superblock follows");
- qdm2_decode_super_block();
- }
-
- // parse subpackets
- debug(1, "QDM2Stream::qdm2_decodeFrame parse subpackets");
- if (!_hasErrors) {
- if (_subPacket == 2) {
- debug(1, "QDM2Stream::qdm2_decodeFrame qdm2_decode_fft_packets()");
- qdm2_decode_fft_packets();
- }
-
- debug(1, "QDM2Stream::qdm2_decodeFrame qdm2_fft_tone_synthesizer(%d)", _subPacket);
- qdm2_fft_tone_synthesizer(_subPacket);
- }
-
- // sound synthesis stage 1 (FFT)
- debug(1, "QDM2Stream::qdm2_decodeFrame sound synthesis stage 1 (FFT)");
- for (ch = 0; ch < _channels; ch++) {
- qdm2_calculate_fft(ch);
-
- if (!_hasErrors && _subPacketListC[0].packet != NULL) {
- error("QDM2 : has errors, and C list is not empty");
- return 0;
- }
- }
-
- // sound synthesis stage 2 (MPEG audio like synthesis filter)
- debug(1, "QDM2Stream::qdm2_decodeFrame sound synthesis stage 2 (MPEG audio like synthesis filter)");
- if (!_hasErrors && _doSynthFilter)
- qdm2_synthesis_filter(_subPacket);
-
- _subPacket = (_subPacket + 1) % 16;
-
- if(_hasErrors)
- warning("QDM2 Packet error...");
-
- // clip and convert output float[] to 16bit signed samples
- debug(1, "QDM2Stream::qdm2_decodeFrame clip and convert output float[] to 16bit signed samples");
-
-/*
- debugN(1, "Input Data Packet:");
- for(i = 0; i < _packetSize; i++) {
- debugN(1, " %d", _compressedData[i]);
- }
- debugN(1, " Output Data Packet:");
- for(i = 0; i < frame_size; i++) {
- debugN(1, " %d", (int)_outputBuffer[i]);
- }
- debug(1, "");
-*/
-
- for (i = 0; i < frame_size; i++) {
- //debug(1, "QDM2Stream::qdm2_decodeFrame i: %d", i);
- int value = (int)_outputBuffer[i];
-
- if (value > SOFTCLIP_THRESHOLD)
- value = (value > HARDCLIP_THRESHOLD) ? 32767 : _softclipTable[ value - SOFTCLIP_THRESHOLD];
- else if (value < -SOFTCLIP_THRESHOLD)
- value = (value < -HARDCLIP_THRESHOLD) ? -32767 : -_softclipTable[-value - SOFTCLIP_THRESHOLD];
-
- _outputSamples.push_back(value);
- }
- return frame_size;
-}
-
-int QDM2Stream::readBuffer(int16 *buffer, const int numSamples) {
- debug(1, "QDM2Stream::readBuffer numSamples: %d", numSamples);
- int32 decodedSamples = _outputSamples.size();
- int32 i;
-
- //while((int)_outputSamples.size() < numSamples) {
- while(!_stream->eos() && _stream->pos() != _stream->size()) {
- i = qdm2_decodeFrame(_stream);
- if(i == 0)
- break; // Out Of Decode Frames...
- decodedSamples += i;
- }
- if(decodedSamples > numSamples)
- decodedSamples = numSamples;
-
- for(i = 0; i < decodedSamples; i++)
- buffer[i] = _outputSamples.remove_at(0);
-
- return decodedSamples;
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qdm2.h b/engines/mohawk/video/qdm2.h
deleted file mode 100644
index ffa5f77030..0000000000
--- a/engines/mohawk/video/qdm2.h
+++ /dev/null
@@ -1,289 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_VIDEO_QDM2_H
-#define MOHAWK_VIDEO_QDM2_H
-
-#include "sound/audiostream.h"
-#include "common/array.h"
-#include "common/stream.h"
-
-namespace Mohawk {
-
-enum {
- SOFTCLIP_THRESHOLD = 27600,
- HARDCLIP_THRESHOLD = 35716,
- MPA_MAX_CHANNELS = 2,
- MPA_FRAME_SIZE = 1152,
- FF_INPUT_BUFFER_PADDING_SIZE = 8
-};
-
-typedef int8 sb_int8_array[2][30][64];
-
-/* bit input */
-/* buffer, buffer_end and size_in_bits must be present and used by every reader */
-struct GetBitContext {
- const uint8 *buffer, *bufferEnd;
- int index;
- int sizeInBits;
-};
-
-struct QDM2SubPacket {
- int type;
- unsigned int size;
- const uint8 *data; // pointer to subpacket data (points to input data buffer, it's not a private copy)
-};
-
-struct QDM2SubPNode {
- QDM2SubPacket *packet;
- struct QDM2SubPNode *next; // pointer to next packet in the list, NULL if leaf node
-};
-
-struct QDM2Complex {
- float re;
- float im;
-};
-
-struct FFTTone {
- float level;
- QDM2Complex *complex;
- const float *table;
- int phase;
- int phase_shift;
- int duration;
- short time_index;
- short cutoff;
-};
-
-struct FFTCoefficient {
- int16 sub_packet;
- uint8 channel;
- int16 offset;
- int16 exp;
- uint8 phase;
-};
-
-struct VLC {
- int32 bits;
- int16 (*table)[2]; // code, bits
- int32 table_size;
- int32 table_allocated;
-};
-
-#include "common/pack-start.h"
-struct QDM2FFT {
- QDM2Complex complex[MPA_MAX_CHANNELS][256];
-} PACKED_STRUCT;
-#include "common/pack-end.h"
-
-enum RDFTransformType {
- RDFT,
- IRDFT,
- RIDFT,
- IRIDFT
-};
-
-struct FFTComplex {
- float re, im;
-};
-
-struct FFTContext {
- int nbits;
- int inverse;
- uint16 *revtab;
- FFTComplex *exptab;
- FFTComplex *tmpBuf;
- int mdctSize; // size of MDCT (i.e. number of input data * 2)
- int mdctBits; // n = 2^nbits
- // pre/post rotation tables
- float *tcos;
- float *tsin;
- void (*fftPermute)(struct FFTContext *s, FFTComplex *z);
- void (*fftCalc)(struct FFTContext *s, FFTComplex *z);
- void (*imdctCalc)(struct FFTContext *s, float *output, const float *input);
- void (*imdctHalf)(struct FFTContext *s, float *output, const float *input);
- void (*mdctCalc)(struct FFTContext *s, float *output, const float *input);
- int splitRadix;
- int permutation;
-};
-
-enum {
- FF_MDCT_PERM_NONE = 0,
- FF_MDCT_PERM_INTERLEAVE = 1
-};
-
-struct RDFTContext {
- int nbits;
- int inverse;
- int signConvention;
-
- // pre/post rotation tables
- float *tcos;
- float *tsin;
- FFTContext fft;
-};
-
-class QDM2Stream : public Audio::AudioStream {
-public:
- QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
- ~QDM2Stream();
-
- bool isStereo() const { return _channels == 2; }
- bool endOfData() const { return ((_stream->pos() == _stream->size()) && (_outputSamples.size() == 0)); }
- int getRate() const { return _sampleRate; }
- int readBuffer(int16 *buffer, const int numSamples);
-
-private:
- Common::SeekableReadStream *_stream;
-
- // Parameters from codec header, do not change during playback
- uint8 _channels;
- uint16 _sampleRate;
- uint16 _bitRate;
- uint16 _blockSize; // Group
- uint16 _frameSize; // FFT
- uint16 _packetSize; // Checksum
-
- // Parameters built from header parameters, do not change during playback
- int _groupOrder; // order of frame group
- int _fftOrder; // order of FFT (actually fft order+1)
- int _fftFrameSize; // size of fft frame, in components (1 comples = re + im)
- int _sFrameSize; // size of data frame
- int _frequencyRange;
- int _subSampling; // subsampling: 0=25%, 1=50%, 2=100% */
- int _coeffPerSbSelect; // selector for "num. of coeffs. per subband" tables. Can be 0, 1, 2
- int _cmTableSelect; // selector for "coding method" tables. Can be 0, 1 (from init: 0-4)
-
- // Packets and packet lists
- QDM2SubPacket _subPackets[16]; // the packets themselves
- QDM2SubPNode _subPacketListA[16]; // list of all packets
- QDM2SubPNode _subPacketListB[16]; // FFT packets B are on list
- int _subPacketsB; // number of packets on 'B' list
- QDM2SubPNode _subPacketListC[16]; // packets with errors?
- QDM2SubPNode _subPacketListD[16]; // DCT packets
-
- // FFT and tones
- FFTTone _fftTones[1000];
- int _fftToneStart;
- int _fftToneEnd;
- FFTCoefficient _fftCoefs[1000];
- int _fftCoefsIndex;
- int _fftCoefsMinIndex[5];
- int _fftCoefsMaxIndex[5];
- int _fftLevelExp[6];
- //RDFTContext _rdftCtx;
- QDM2FFT _fft;
-
- // I/O data
- uint8 *_compressedData;
- float _outputBuffer[1024];
- Common::Array<int16> _outputSamples;
-
- // Synthesis filter
- int16 ff_mpa_synth_window[512];
- int16 _synthBuf[MPA_MAX_CHANNELS][512*2];
- int _synthBufOffset[MPA_MAX_CHANNELS];
- int32 _sbSamples[MPA_MAX_CHANNELS][128][32];
-
- // Mixed temporary data used in decoding
- float _toneLevel[MPA_MAX_CHANNELS][30][64];
- int8 _codingMethod[MPA_MAX_CHANNELS][30][64];
- int8 _quantizedCoeffs[MPA_MAX_CHANNELS][10][8];
- int8 _toneLevelIdxBase[MPA_MAX_CHANNELS][30][8];
- int8 _toneLevelIdxHi1[MPA_MAX_CHANNELS][3][8][8];
- int8 _toneLevelIdxMid[MPA_MAX_CHANNELS][26][8];
- int8 _toneLevelIdxHi2[MPA_MAX_CHANNELS][26];
- int8 _toneLevelIdx[MPA_MAX_CHANNELS][30][64];
- int8 _toneLevelIdxTemp[MPA_MAX_CHANNELS][30][64];
-
- // Flags
- bool _hasErrors; // packet has errors
- int _superblocktype_2_3; // select fft tables and some algorithm based on superblock type
- int _doSynthFilter; // used to perform or skip synthesis filter
-
- uint8 _subPacket; // 0 to 15
- int _noiseIdx; // index for dithering noise table
-
- byte _emptyBuffer[FF_INPUT_BUFFER_PADDING_SIZE];
-
- VLC _vlcTabLevel;
- VLC _vlcTabDiff;
- VLC _vlcTabRun;
- VLC _fftLevelExpAltVlc;
- VLC _fftLevelExpVlc;
- VLC _fftStereoExpVlc;
- VLC _fftStereoPhaseVlc;
- VLC _vlcTabToneLevelIdxHi1;
- VLC _vlcTabToneLevelIdxMid;
- VLC _vlcTabToneLevelIdxHi2;
- VLC _vlcTabType30;
- VLC _vlcTabType34;
- VLC _vlcTabFftToneOffset[5];
- bool _vlcsInitialized;
- void initVlc(void);
-
- uint16 _softclipTable[HARDCLIP_THRESHOLD - SOFTCLIP_THRESHOLD + 1];
- void softclipTableInit(void);
-
- float _noiseTable[4096];
- byte _randomDequantIndex[256][5];
- byte _randomDequantType24[128][3];
- void rndTableInit(void);
-
- float _noiseSamples[128];
- void initNoiseSamples(void);
-
- RDFTContext _rdftCtx;
-
- void average_quantized_coeffs(void);
- void build_sb_samples_from_noise(int sb);
- void fix_coding_method_array(int sb, int channels, sb_int8_array coding_method);
- void fill_tone_level_array(int flag);
- void fill_coding_method_array(sb_int8_array tone_level_idx, sb_int8_array tone_level_idx_temp,
- sb_int8_array coding_method, int nb_channels,
- int c, int superblocktype_2_3, int cm_table_select);
- void synthfilt_build_sb_samples(GetBitContext *gb, int length, int sb_min, int sb_max);
- void init_quantized_coeffs_elem0(int8 *quantized_coeffs, GetBitContext *gb, int length);
- void init_tone_level_dequantization(GetBitContext *gb, int length);
- void process_subpacket_9(QDM2SubPNode *node);
- void process_subpacket_10(QDM2SubPNode *node, int length);
- void process_subpacket_11(QDM2SubPNode *node, int length);
- void process_subpacket_12(QDM2SubPNode *node, int length);
- void process_synthesis_subpackets(QDM2SubPNode *list);
- void qdm2_decode_super_block(void);
- void qdm2_fft_init_coefficient(int sub_packet, int offset, int duration,
- int channel, int exp, int phase);
- void qdm2_fft_decode_tones(int duration, GetBitContext *gb, int b);
- void qdm2_decode_fft_packets(void);
- void qdm2_fft_generate_tone(FFTTone *tone);
- void qdm2_fft_tone_synthesizer(uint8 sub_packet);
- void qdm2_calculate_fft(int channel);
- void qdm2_synthesis_filter(uint8 index);
- int qdm2_decodeFrame(Common::SeekableReadStream *in);
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/qdm2data.h b/engines/mohawk/video/qdm2data.h
deleted file mode 100644
index f1c18db41c..0000000000
--- a/engines/mohawk/video/qdm2data.h
+++ /dev/null
@@ -1,531 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_VIDEO_QDM2DATA_H
-#define MOHAWK_VIDEO_QDM2DATA_H
-
-#include "common/scummsys.h"
-
-namespace Mohawk {
-
-/// VLC TABLES
-
-// values in this table range from -1..23; adjust retrieved value by -1
-static const uint16 vlc_tab_level_huffcodes[24] = {
- 0x037c, 0x0004, 0x003c, 0x004c, 0x003a, 0x002c, 0x001c, 0x001a,
- 0x0024, 0x0014, 0x0001, 0x0002, 0x0000, 0x0003, 0x0007, 0x0005,
- 0x0006, 0x0008, 0x0009, 0x000a, 0x000c, 0x00fc, 0x007c, 0x017c
-};
-
-static const byte vlc_tab_level_huffbits[24] = {
- 10, 6, 7, 7, 6, 6, 6, 6, 6, 5, 4, 4, 4, 3, 3, 3, 3, 4, 4, 5, 7, 8, 9, 10
-};
-
-// values in this table range from -1..36; adjust retrieved value by -1
-static const uint16 vlc_tab_diff_huffcodes[37] = {
- 0x1c57, 0x0004, 0x0000, 0x0001, 0x0003, 0x0002, 0x000f, 0x000e,
- 0x0007, 0x0016, 0x0037, 0x0027, 0x0026, 0x0066, 0x0006, 0x0097,
- 0x0046, 0x01c6, 0x0017, 0x0786, 0x0086, 0x0257, 0x00d7, 0x0357,
- 0x00c6, 0x0386, 0x0186, 0x0000, 0x0157, 0x0c57, 0x0057, 0x0000,
- 0x0b86, 0x0000, 0x1457, 0x0000, 0x0457
-};
-
-static const byte vlc_tab_diff_huffbits[37] = {
- 13, 3, 3, 2, 3, 3, 4, 4, 6, 5, 6, 6, 7, 7, 8, 8,
- 8, 9, 8, 11, 9, 10, 8, 10, 9, 12, 10, 0, 10, 13, 11, 0,
- 12, 0, 13, 0, 13
-};
-
-// values in this table range from -1..5; adjust retrieved value by -1
-static const byte vlc_tab_run_huffcodes[6] = {
- 0x1f, 0x00, 0x01, 0x03, 0x07, 0x0f
-};
-
-static const byte vlc_tab_run_huffbits[6] = {
- 5, 1, 2, 3, 4, 5
-};
-
-// values in this table range from -1..19; adjust retrieved value by -1
-static const uint16 vlc_tab_tone_level_idx_hi1_huffcodes[20] = {
- 0x5714, 0x000c, 0x0002, 0x0001, 0x0000, 0x0004, 0x0034, 0x0054,
- 0x0094, 0x0014, 0x0114, 0x0214, 0x0314, 0x0614, 0x0e14, 0x0f14,
- 0x2714, 0x0714, 0x1714, 0x3714
-};
-
-static const byte vlc_tab_tone_level_idx_hi1_huffbits[20] = {
- 15, 4, 2, 1, 3, 5, 6, 7, 8, 10, 10, 11, 11, 12, 12, 12, 14, 14, 15, 14
-};
-
-// values in this table range from -1..23; adjust retrieved value by -1
-static const uint16 vlc_tab_tone_level_idx_mid_huffcodes[24] = {
- 0x0fea, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x03ea, 0x00ea, 0x002a, 0x001a,
- 0x0006, 0x0001, 0x0000, 0x0002, 0x000a, 0x006a, 0x01ea, 0x07ea
-};
-
-static const byte vlc_tab_tone_level_idx_mid_huffbits[24] = {
- 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 7, 5, 3, 1, 2, 4, 6, 8, 10, 12
-};
-
-// values in this table range from -1..23; adjust retrieved value by -1
-static const uint16 vlc_tab_tone_level_idx_hi2_huffcodes[24] = {
- 0x0664, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0064, 0x00e4,
- 0x00a4, 0x0068, 0x0004, 0x0008, 0x0014, 0x0018, 0x0000, 0x0001,
- 0x0002, 0x0003, 0x000c, 0x0028, 0x0024, 0x0164, 0x0000, 0x0264
-};
-
-static const byte vlc_tab_tone_level_idx_hi2_huffbits[24] = {
- 11, 0, 0, 0, 0, 0, 10, 8, 8, 7, 6, 6, 5, 5, 4, 2, 2, 2, 4, 7, 8, 9, 0, 11
-};
-
-// values in this table range from -1..8; adjust retrieved value by -1
-static const byte vlc_tab_type30_huffcodes[9] = {
- 0x3c, 0x06, 0x00, 0x01, 0x03, 0x02, 0x04, 0x0c, 0x1c
-};
-
-static const byte vlc_tab_type30_huffbits[9] = {
- 6, 3, 3, 2, 2, 3, 4, 5, 6
-};
-
-// values in this table range from -1..9; adjust retrieved value by -1
-static const byte vlc_tab_type34_huffcodes[10] = {
- 0x18, 0x00, 0x01, 0x04, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08
-};
-
-static const byte vlc_tab_type34_huffbits[10] = {
- 5, 4, 3, 3, 3, 3, 3, 3, 3, 5
-};
-
-// values in this table range from -1..22; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_0_huffcodes[23] = {
- 0x038e, 0x0001, 0x0000, 0x0022, 0x000a, 0x0006, 0x0012, 0x0002,
- 0x001e, 0x003e, 0x0056, 0x0016, 0x000e, 0x0032, 0x0072, 0x0042,
- 0x008e, 0x004e, 0x00f2, 0x002e, 0x0036, 0x00c2, 0x018e
-};
-
-static const byte vlc_tab_fft_tone_offset_0_huffbits[23] = {
- 10, 1, 2, 6, 4, 5, 6, 7, 6, 6, 7, 7, 8, 7, 8, 8, 9, 7, 8, 6, 6, 8, 10
-};
-
-// values in this table range from -1..27; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_1_huffcodes[28] = {
- 0x07a4, 0x0001, 0x0020, 0x0012, 0x001c, 0x0008, 0x0006, 0x0010,
- 0x0000, 0x0014, 0x0004, 0x0032, 0x0070, 0x000c, 0x0002, 0x003a,
- 0x001a, 0x002c, 0x002a, 0x0022, 0x0024, 0x000a, 0x0064, 0x0030,
- 0x0062, 0x00a4, 0x01a4, 0x03a4
-};
-
-static const byte vlc_tab_fft_tone_offset_1_huffbits[28] = {
- 11, 1, 6, 6, 5, 4, 3, 6, 6, 5, 6, 6, 7, 6, 6, 6,
- 6, 6, 6, 7, 8, 6, 7, 7, 7, 9, 10, 11
-};
-
-// values in this table range from -1..31; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_2_huffcodes[32] = {
- 0x1760, 0x0001, 0x0000, 0x0082, 0x000c, 0x0006, 0x0003, 0x0007,
- 0x0008, 0x0004, 0x0010, 0x0012, 0x0022, 0x001a, 0x0000, 0x0020,
- 0x000a, 0x0040, 0x004a, 0x006a, 0x002a, 0x0042, 0x0002, 0x0060,
- 0x00aa, 0x00e0, 0x00c2, 0x01c2, 0x0160, 0x0360, 0x0760, 0x0f60
-};
-
-static const byte vlc_tab_fft_tone_offset_2_huffbits[32] = {
- 13, 2, 0, 8, 4, 3, 3, 3, 4, 4, 5, 5, 6, 5, 7, 7,
- 7, 7, 7, 7, 8, 8, 8, 9, 8, 8, 9, 9, 10, 11, 13, 12
-};
-
-// values in this table range from -1..34; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_3_huffcodes[35] = {
- 0x33ea, 0x0005, 0x0000, 0x000c, 0x0000, 0x0006, 0x0003, 0x0008,
- 0x0002, 0x0001, 0x0004, 0x0007, 0x001a, 0x000f, 0x001c, 0x002c,
- 0x000a, 0x001d, 0x002d, 0x002a, 0x000d, 0x004c, 0x008c, 0x006a,
- 0x00cd, 0x004d, 0x00ea, 0x020c, 0x030c, 0x010c, 0x01ea, 0x07ea,
- 0x0bea, 0x03ea, 0x13ea
-};
-
-static const byte vlc_tab_fft_tone_offset_3_huffbits[35] = {
- 14, 4, 0, 10, 4, 3, 3, 4, 4, 3, 4, 4, 5, 4, 5, 6,
- 6, 5, 6, 7, 7, 7, 8, 8, 8, 8, 9, 10, 10, 10, 10, 11,
- 12, 13, 14
-};
-
-// values in this table range from -1..37; adjust retrieved value by -1
-static const uint16 vlc_tab_fft_tone_offset_4_huffcodes[38] = {
- 0x5282, 0x0016, 0x0000, 0x0136, 0x0004, 0x0000, 0x0007, 0x000a,
- 0x000e, 0x0003, 0x0001, 0x000d, 0x0006, 0x0009, 0x0012, 0x0005,
- 0x0025, 0x0022, 0x0015, 0x0002, 0x0076, 0x0035, 0x0042, 0x00c2,
- 0x0182, 0x00b6, 0x0036, 0x03c2, 0x0482, 0x01c2, 0x0682, 0x0882,
- 0x0a82, 0x0082, 0x0282, 0x1282, 0x3282, 0x2282
-};
-
-static const byte vlc_tab_fft_tone_offset_4_huffbits[38] = {
- 15, 6, 0, 9, 3, 3, 3, 4, 4, 3, 4, 4, 5, 4, 5, 6,
- 6, 6, 6, 8, 7, 6, 8, 9, 9, 8, 9, 10, 11, 10, 11, 12,
- 12, 12, 14, 15, 14, 14
-};
-
-/// FFT TABLES
-
-// values in this table range from -1..27; adjust retrieved value by -1
-static const uint16 fft_level_exp_alt_huffcodes[28] = {
- 0x1ec6, 0x0006, 0x00c2, 0x0142, 0x0242, 0x0246, 0x00c6, 0x0046,
- 0x0042, 0x0146, 0x00a2, 0x0062, 0x0026, 0x0016, 0x000e, 0x0005,
- 0x0004, 0x0003, 0x0000, 0x0001, 0x000a, 0x0012, 0x0002, 0x0022,
- 0x01c6, 0x02c6, 0x06c6, 0x0ec6
-};
-
-static const byte fft_level_exp_alt_huffbits[28] = {
- 13, 7, 8, 9, 10, 10, 10, 10, 10, 9, 8, 7, 6, 5, 4, 3,
- 3, 2, 3, 3, 4, 5, 7, 8, 9, 11, 12, 13
-};
-
-// values in this table range from -1..19; adjust retrieved value by -1
-static const uint16 fft_level_exp_huffcodes[20] = {
- 0x0f24, 0x0001, 0x0002, 0x0000, 0x0006, 0x0005, 0x0007, 0x000c,
- 0x000b, 0x0014, 0x0013, 0x0004, 0x0003, 0x0023, 0x0064, 0x00a4,
- 0x0024, 0x0124, 0x0324, 0x0724
-};
-
-static const byte fft_level_exp_huffbits[20] = {
- 12, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 10, 11, 12
-};
-
-// values in this table range from -1..6; adjust retrieved value by -1
-static const byte fft_stereo_exp_huffcodes[7] = {
- 0x3e, 0x01, 0x00, 0x02, 0x06, 0x0e, 0x1e
-};
-
-static const byte fft_stereo_exp_huffbits[7] = {
- 6, 1, 2, 3, 4, 5, 6
-};
-
-// values in this table range from -1..8; adjust retrieved value by -1
-static const byte fft_stereo_phase_huffcodes[9] = {
- 0x35, 0x02, 0x00, 0x01, 0x0d, 0x15, 0x05, 0x09, 0x03
-};
-
-static const byte fft_stereo_phase_huffbits[9] = {
- 6, 2, 2, 4, 4, 6, 5, 4, 2
-};
-
-static const int fft_cutoff_index_table[4][2] = {
- { 1, 2 }, {-1, 0 }, {-1,-2 }, { 0, 0 }
-};
-
-static const int16 fft_level_index_table[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-};
-
-static const byte last_coeff[3] = {
- 4, 7, 10
-};
-
-static const byte coeff_per_sb_for_avg[3][30] = {
- { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
- { 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 },
- { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9 }
-};
-
-static const uint32 dequant_table[3][10][30] = {
- { { 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 256, 256, 205, 154, 102, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 51, 102, 154, 205, 256, 238, 219, 201, 183, 165, 146, 128, 110, 91, 73, 55, 37, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 18, 37, 55, 73, 91, 110, 128, 146, 165, 183, 201, 219, 238, 256, 228, 199, 171, 142, 114, 85, 57, 28 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
- { { 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 85, 171, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 85, 171, 256, 219, 183, 146, 110, 73, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 73, 110, 146, 183, 219, 256, 228, 199, 171, 142, 114, 85, 57, 28, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 57, 85, 114, 142, 171, 199, 228, 256, 213, 171, 128, 85, 43 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
- { { 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 256, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 85, 171, 256, 192, 128, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 128, 192, 256, 205, 154, 102, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 102, 154, 205, 256, 213, 171, 128, 85, 43, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 85, 128, 171, 213, 256, 213, 171, 128, 85, 43 } }
-};
-
-static const byte coeff_per_sb_for_dequant[3][30] = {
- { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
- { 0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6 },
- { 0, 1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9 }
-};
-
-// first index is subband, 2nd index is 0, 1 or 3 (2 is unused)
-static const int8 tone_level_idx_offset_table[30][4] = {
- { -50, -50, 0, -50 },
- { -50, -50, 0, -50 },
- { -50, -9, 0, -19 },
- { -16, -6, 0, -12 },
- { -11, -4, 0, -8 },
- { -8, -3, 0, -6 },
- { -7, -3, 0, -5 },
- { -6, -2, 0, -4 },
- { -5, -2, 0, -3 },
- { -4, -1, 0, -3 },
- { -4, -1, 0, -2 },
- { -3, -1, 0, -2 },
- { -3, -1, 0, -2 },
- { -3, -1, 0, -2 },
- { -2, -1, 0, -1 },
- { -2, -1, 0, -1 },
- { -2, -1, 0, -1 },
- { -2, 0, 0, -1 },
- { -2, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, -1 },
- { -1, 0, 0, 0 },
- { -1, 0, 0, 0 },
- { -1, 0, 0, 0 },
- { -1, 0, 0, 0 }
-};
-
-/* all my samples have 1st index 0 or 1 */
-/* second index is subband, only indexes 0-29 seem to be used */
-static const int8 coding_method_table[5][30] = {
- { 34, 30, 24, 24, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
- },
- { 34, 30, 24, 24, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
- },
- { 34, 30, 30, 30, 24, 24, 16, 16, 16, 16, 16, 16, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
- },
- { 34, 34, 30, 30, 24, 24, 24, 24, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10, 10
- },
- { 34, 34, 30, 30, 30, 30, 30, 30, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
- },
-};
-
-static const int vlc_stage3_values[60] = {
- 0, 1, 2, 3, 4, 6, 8, 10, 12, 16, 20, 24,
- 28, 36, 44, 52, 60, 76, 92, 108, 124, 156, 188, 220,
- 252, 316, 380, 444, 508, 636, 764, 892, 1020, 1276, 1532, 1788,
- 2044, 2556, 3068, 3580, 4092, 5116, 6140, 7164, 8188, 10236, 12284, 14332,
- 16380, 20476, 24572, 28668, 32764, 40956, 49148, 57340, 65532, 81916, 98300,114684
-};
-
-static const float fft_tone_sample_table[4][16][5] = {
- { { .0100000000f,-.0037037037f,-.0020000000f,-.0069444444f,-.0018416207f },
- { .0416666667f, .0000000000f, .0000000000f,-.0208333333f,-.0123456791f },
- { .1250000000f, .0558035709f, .0330687836f,-.0164473690f,-.0097465888f },
- { .1562500000f, .0625000000f, .0370370370f,-.0062500000f,-.0037037037f },
- { .1996007860f, .0781250000f, .0462962948f, .0022727272f, .0013468013f },
- { .2000000000f, .0625000000f, .0370370373f, .0208333333f, .0074074073f },
- { .2127659619f, .0555555556f, .0329218097f, .0208333333f, .0123456791f },
- { .2173913121f, .0473484844f, .0280583613f, .0347222239f, .0205761325f },
- { .2173913121f, .0347222239f, .0205761325f, .0473484844f, .0280583613f },
- { .2127659619f, .0208333333f, .0123456791f, .0555555556f, .0329218097f },
- { .2000000000f, .0208333333f, .0074074073f, .0625000000f, .0370370370f },
- { .1996007860f, .0022727272f, .0013468013f, .0781250000f, .0462962948f },
- { .1562500000f,-.0062500000f,-.0037037037f, .0625000000f, .0370370370f },
- { .1250000000f,-.0164473690f,-.0097465888f, .0558035709f, .0330687836f },
- { .0416666667f,-.0208333333f,-.0123456791f, .0000000000f, .0000000000f },
- { .0100000000f,-.0069444444f,-.0018416207f,-.0037037037f,-.0020000000f } },
-
- { { .0050000000f,-.0200000000f, .0125000000f,-.3030303030f, .0020000000f },
- { .1041666642f, .0400000000f,-.0250000000f, .0333333333f,-.0200000000f },
- { .1250000000f, .0100000000f, .0142857144f,-.0500000007f,-.0200000000f },
- { .1562500000f,-.0006250000f,-.00049382716f,-.000625000f,-.00049382716f },
- { .1562500000f,-.0006250000f,-.00049382716f,-.000625000f,-.00049382716f },
- { .1250000000f,-.0500000000f,-.0200000000f, .0100000000f, .0142857144f },
- { .1041666667f, .0333333333f,-.0200000000f, .0400000000f,-.0250000000f },
- { .0050000000f,-.3030303030f, .0020000001f,-.0200000000f, .0125000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f } },
-
- { { .1428571492f, .1250000000f,-.0285714287f,-.0357142873f, .0208333333f },
- { .1818181818f, .0588235296f, .0333333333f, .0212765951f, .0100000000f },
- { .1818181818f, .0212765951f, .0100000000f, .0588235296f, .0333333333f },
- { .1428571492f,-.0357142873f, .0208333333f, .1250000000f,-.0285714287f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f } },
-
- { { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f },
- { .0000000000f, .0000000000f, .0000000000f, .0000000000f, .0000000000f } }
-};
-
-static const float fft_tone_level_table[2][64] = { {
-// pow ~ (i > 46) ? 0 : (((((i & 1) ? 431 : 304) << (i >> 1))) / 1024.0);
- 0.17677669f, 0.42677650f, 0.60355347f, 0.85355347f,
- 1.20710683f, 1.68359375f, 2.37500000f, 3.36718750f,
- 4.75000000f, 6.73437500f, 9.50000000f, 13.4687500f,
- 19.0000000f, 26.9375000f, 38.0000000f, 53.8750000f,
- 76.0000000f, 107.750000f, 152.000000f, 215.500000f,
- 304.000000f, 431.000000f, 608.000000f, 862.000000f,
- 1216.00000f, 1724.00000f, 2432.00000f, 3448.00000f,
- 4864.00000f, 6896.00000f, 9728.00000f, 13792.0000f,
- 19456.0000f, 27584.0000f, 38912.0000f, 55168.0000f,
- 77824.0000f, 110336.000f, 155648.000f, 220672.000f,
- 311296.000f, 441344.000f, 622592.000f, 882688.000f,
- 1245184.00f, 1765376.00f, 2490368.00f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- }, {
-// pow = (i > 45) ? 0 : ((((i & 1) ? 431 : 304) << (i >> 1)) / 512.0);
- 0.59375000f, 0.84179688f, 1.18750000f, 1.68359375f,
- 2.37500000f, 3.36718750f, 4.75000000f, 6.73437500f,
- 9.50000000f, 13.4687500f, 19.0000000f, 26.9375000f,
- 38.0000000f, 53.8750000f, 76.0000000f, 107.750000f,
- 152.000000f, 215.500000f, 304.000000f, 431.000000f,
- 608.000000f, 862.000000f, 1216.00000f, 1724.00000f,
- 2432.00000f, 3448.00000f, 4864.00000f, 6896.00000f,
- 9728.00000f, 13792.0000f, 19456.0000f, 27584.0000f,
- 38912.0000f, 55168.0000f, 77824.0000f, 110336.000f,
- 155648.000f, 220672.000f, 311296.000f, 441344.000f,
- 622592.000f, 882688.000f, 1245184.00f, 1765376.00f,
- 2490368.00f, 3530752.00f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
- 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f
-} };
-
-static const float fft_tone_envelope_table[4][31] = {
- { .009607375f, .038060248f, .084265202f, .146446645f, .222214907f, .308658302f,
- .402454883f, .500000060f, .597545207f, .691341758f, .777785182f, .853553414f,
- .915734828f, .961939812f, .990392685f, 1.00000000f, .990392625f, .961939752f,
- .915734768f, .853553295f, .777785063f, .691341639f, .597545087f, .500000000f,
- .402454853f, .308658272f, .222214878f, .146446615f, .084265172f, .038060218f,
- .009607345f },
- { .038060248f, .146446645f, .308658302f, .500000060f, .691341758f, .853553414f,
- .961939812f, 1.00000000f, .961939752f, .853553295f, .691341639f, .500000000f,
- .308658272f, .146446615f, .038060218f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f },
- { .146446645f, .500000060f, .853553414f, 1.00000000f, .853553295f, .500000000f,
- .146446615f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f },
- { .500000060f, 1.00000000f, .500000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f, .000000000f, .000000000f, .000000000f, .000000000f, .000000000f,
- .000000000f }
-};
-
-static const float sb_noise_attenuation[32] = {
- 0.0f, 0.0f, 0.3f, 0.4f, 0.5f, 0.7f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
- 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-};
-
-static const byte fft_subpackets[32] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0
-};
-
-// first index is joined_stereo, second index is 0 or 2 (1 is unused)
-static const float dequant_1bit[2][3] = {
- {-0.920000f, 0.000000f, 0.920000f },
- {-0.890000f, 0.000000f, 0.890000f }
-};
-
-static const float type30_dequant[8] = {
- -1.0f,-0.625f,-0.291666656732559f,0.0f,
- 0.25f,0.5f,0.75f,1.0f,
-};
-
-static const float type34_delta[10] = { // FIXME: covers 8 entries..
- -1.0f,-0.60947573184967f,-0.333333343267441f,-0.138071194291115f,0.0f,
- 0.138071194291115f,0.333333343267441f,0.60947573184967f,1.0f,0.0f,
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/qt_player.cpp b/engines/mohawk/video/qt_player.cpp
deleted file mode 100644
index 0ed05bb84d..0000000000
--- a/engines/mohawk/video/qt_player.cpp
+++ /dev/null
@@ -1,1272 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-//
-// Heavily based on ffmpeg code.
-//
-// Copyright (c) 2001 Fabrice Bellard.
-// First version by Francois Revol revol@free.fr
-// Seek function by Gael Chardon gael.dev@4now.net
-//
-
-#include "mohawk/video/qt_player.h"
-
-#include "common/debug.h"
-#include "common/endian.h"
-#include "common/util.h"
-#include "common/zlib.h"
-
-// Audio codecs
-#include "sound/decoders/adpcm.h"
-#include "sound/decoders/raw.h"
-#include "mohawk/video/qdm2.h"
-
-// Video codecs
-#include "mohawk/jpeg.h"
-#include "mohawk/video/cinepak.h"
-#include "mohawk/video/qtrle.h"
-#include "mohawk/video/rpza.h"
-#include "mohawk/video/smc.h"
-
-namespace Mohawk {
-
-////////////////////////////////////////////
-// QTPlayer
-////////////////////////////////////////////
-
-QTPlayer::QTPlayer() : Graphics::VideoDecoder() {
- _audStream = NULL;
- _beginOffset = 0;
- _videoCodec = NULL;
- _curFrame = -1;
- _startTime = _nextFrameStartTime = 0;
- _audHandle = Audio::SoundHandle();
- _numStreams = 0;
- _fd = 0;
- _scaledSurface = 0;
- _dirtyPalette = false;
-}
-
-QTPlayer::~QTPlayer() {
- close();
-}
-
-uint16 QTPlayer::getWidth() const {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->width / getScaleMode();
-}
-
-uint16 QTPlayer::getHeight() const {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->height / getScaleMode();
-}
-
-uint32 QTPlayer::getFrameCount() const {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->nb_frames;
-}
-
-byte QTPlayer::getBitsPerPixel() {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->bits_per_sample & 0x1F;
-}
-
-uint32 QTPlayer::getCodecTag() {
- if (_videoStreamIndex < 0)
- return 0;
-
- return _streams[_videoStreamIndex]->codec_tag;
-}
-
-ScaleMode QTPlayer::getScaleMode() const {
- if (_videoStreamIndex < 0)
- return kScaleNormal;
-
- return (ScaleMode)(_scaleMode * _streams[_videoStreamIndex]->scaleMode);
-}
-
-uint32 QTPlayer::getFrameDuration() {
- if (_videoStreamIndex < 0)
- return 0;
-
- uint32 curFrameIndex = 0;
- for (int32 i = 0; i < _streams[_videoStreamIndex]->stts_count; i++) {
- curFrameIndex += _streams[_videoStreamIndex]->stts_data[i].count;
- if ((uint32)_curFrame < curFrameIndex) {
- // Ok, now we have what duration this frame has.
- return _streams[_videoStreamIndex]->stts_data[i].duration;
- }
- }
-
- // This should never occur
- error ("Cannot find duration for frame %d", _curFrame);
- return 0;
-}
-
-Graphics::PixelFormat QTPlayer::getPixelFormat() const {
- if (!_videoCodec)
- return Graphics::PixelFormat::createFormatCLUT8();
-
- return _videoCodec->getPixelFormat();
-}
-
-void QTPlayer::rewind() {
- delete _videoCodec; _videoCodec = NULL;
- _curFrame = -1;
- _startTime = _nextFrameStartTime = 0;
-
- // Restart the audio too
- stopAudio();
- if (_audioStreamIndex >= 0) {
- _curAudioChunk = 0;
- _audStream = Audio::makeQueuingAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels == 2);
- }
- startAudio();
-}
-
-Graphics::Codec *QTPlayer::createCodec(uint32 codecTag, byte bitsPerPixel) {
- if (codecTag == MKID_BE('cvid')) {
- // Cinepak: As used by most Myst and all Riven videos as well as some Myst ME videos. "The Chief" videos also use this.
- return new CinepakDecoder();
- } else if (codecTag == MKID_BE('rpza')) {
- // Apple Video ("Road Pizza"): Used by some Myst videos.
- return new RPZADecoder(getWidth(), getHeight());
- } else if (codecTag == MKID_BE('rle ')) {
- // QuickTime RLE: Used by some Myst ME videos.
- return new QTRLEDecoder(getWidth(), getHeight(), bitsPerPixel);
- } else if (codecTag == MKID_BE('smc ')) {
- // Apple SMC: Used by some Myst videos.
- return new SMCDecoder(getWidth(), getHeight());
- } else if (codecTag == MKID_BE('SVQ1')) {
- // Sorenson Video 1: Used by some Myst ME videos.
- warning ("Sorenson Video 1 not yet supported");
- } else if (codecTag == MKID_BE('SVQ3')) {
- // Sorenson Video 3: Used by some Myst ME videos.
- warning ("Sorenson Video 3 not yet supported");
- } else if (codecTag == MKID_BE('jpeg')) {
- // Motion JPEG: Used by some Myst ME 10th Anniversary videos.
- return new JPEGDecoder(true);
- } else if (codecTag == MKID_BE('QkBk')) {
- // CDToons: Used by most of the Broderbund games. This is an unknown format so far.
- warning ("CDToons not yet supported");
- } else {
- warning ("Unsupported codec \'%s\'", tag2str(codecTag));
- }
-
- return NULL;
-}
-
-void QTPlayer::startAudio() {
- if (_audStream) // No audio/audio not supported
- g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream);
-}
-
-void QTPlayer::stopAudio() {
- if (_audStream) {
- g_system->getMixer()->stopHandle(_audHandle);
- _audStream = NULL; // the mixer automatically frees the stream
- }
-}
-
-void QTPlayer::pauseVideoIntern(bool pause) {
- if (_audStream)
- g_system->getMixer()->pauseHandle(_audHandle, pause);
-}
-
-Graphics::Surface *QTPlayer::decodeNextFrame() {
- if (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1)
- return NULL;
-
- if (_startTime == 0)
- _startTime = g_system->getMillis();
-
- _curFrame++;
- _nextFrameStartTime += getFrameDuration();
-
- Common::SeekableReadStream *frameData = getNextFramePacket();
-
- if (frameData) {
- Graphics::Surface *frame = _videoCodec->decodeImage(frameData);
- delete frameData;
- return scaleSurface(frame);
- }
-
- return NULL;
-}
-
-Graphics::Surface *QTPlayer::scaleSurface(Graphics::Surface *frame) {
- if (getScaleMode() == kScaleNormal)
- return frame;
-
- assert(_scaledSurface);
-
- for (uint32 j = 0; j < _scaledSurface->h; j++)
- for (uint32 k = 0; k < _scaledSurface->w; k++)
- memcpy(_scaledSurface->getBasePtr(k, j), frame->getBasePtr(k * getScaleMode(), j * getScaleMode()), frame->bytesPerPixel);
-
- return _scaledSurface;
-}
-
-bool QTPlayer::endOfVideo() const {
- return (!_audStream || _audStream->endOfData()) && (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1);
-}
-
-bool QTPlayer::needsUpdate() const {
- return !endOfVideo() && getTimeToNextFrame() == 0;
-}
-
-uint32 QTPlayer::getElapsedTime() const {
- if (_audStream)
- return g_system->getMixer()->getSoundElapsedTime(_audHandle);
-
- return g_system->getMillis() - _startTime;
-}
-
-uint32 QTPlayer::getTimeToNextFrame() const {
- if (endOfVideo() || _curFrame < 0)
- return 0;
-
- // Convert from the Sega FILM base to 1000
- uint32 nextFrameStartTime = _nextFrameStartTime * 1000 / _streams[_videoStreamIndex]->time_scale;
- uint32 elapsedTime = getElapsedTime();
-
- if (nextFrameStartTime <= elapsedTime)
- return 0;
-
- return nextFrameStartTime - elapsedTime;
-}
-
-bool QTPlayer::load(Common::SeekableReadStream &stream) {
- _fd = &stream;
- _foundMOOV = _foundMDAT = false;
- _numStreams = 0;
- _partial = 0;
- _videoStreamIndex = _audioStreamIndex = -1;
- _startTime = 0;
-
- initParseTable();
-
- MOVatom atom = { 0, 0, 0xffffffff };
-
- if (readDefault(atom) < 0 || (!_foundMOOV && !_foundMDAT))
- return false;
-
- debug(0, "on_parse_exit_offset=%d", _fd->pos());
-
- // some cleanup : make sure we are on the mdat atom
- if((uint32)_fd->pos() != _mdatOffset)
- _fd->seek(_mdatOffset, SEEK_SET);
-
- _next_chunk_offset = _mdatOffset; // initialise reading
-
- for (uint32 i = 0; i < _numStreams;) {
- if (_streams[i]->codec_type == CODEC_TYPE_MOV_OTHER) {// not audio, not video, delete
- delete _streams[i];
- for (uint32 j = i + 1; j < _numStreams; j++)
- _streams[j - 1] = _streams[j];
- _numStreams--;
- } else
- i++;
- }
-
- for (uint32 i = 0; i < _numStreams; i++) {
- MOVStreamContext *sc = _streams[i];
-
- if(!sc->time_rate)
- sc->time_rate = 1;
-
- if(!sc->time_scale)
- sc->time_scale = _timeScale;
-
- //av_set_pts_info(s->streams[i], 64, sc->time_rate, sc->time_scale);
-
- sc->duration /= sc->time_rate;
-
- sc->ffindex = i;
- sc->is_ff_stream = 1;
-
- if (sc->codec_type == CODEC_TYPE_VIDEO && _videoStreamIndex < 0)
- _videoStreamIndex = i;
- else if (sc->codec_type == CODEC_TYPE_AUDIO && _audioStreamIndex < 0)
- _audioStreamIndex = i;
- }
-
- if (_audioStreamIndex >= 0 && checkAudioCodecSupport(_streams[_audioStreamIndex]->codec_tag)) {
- _audStream = Audio::makeQueuingAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels == 2);
- _curAudioChunk = 0;
-
- // Make sure the bits per sample transfers to the sample size
- if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('raw ') || _streams[_audioStreamIndex]->codec_tag == MKID_BE('twos'))
- _streams[_audioStreamIndex]->sample_size = (_streams[_audioStreamIndex]->bits_per_sample / 8) * _streams[_audioStreamIndex]->channels;
-
- startAudio();
- }
-
- if (_videoStreamIndex >= 0) {
- _videoCodec = createCodec(getCodecTag(), getBitsPerPixel());
-
- if (getScaleMode() != kScaleNormal) {
- // We have to initialize the scaled surface
- _scaledSurface = new Graphics::Surface();
- _scaledSurface->create(getWidth(), getHeight(), getPixelFormat().bytesPerPixel);
- }
- }
-
- return true;
-}
-
-void QTPlayer::initParseTable() {
- static const ParseTable p[] = {
- { MKID_BE('dinf'), &QTPlayer::readDefault },
- { MKID_BE('dref'), &QTPlayer::readLeaf },
- { MKID_BE('edts'), &QTPlayer::readDefault },
- { MKID_BE('elst'), &QTPlayer::readELST },
- { MKID_BE('hdlr'), &QTPlayer::readHDLR },
- { MKID_BE('mdat'), &QTPlayer::readMDAT },
- { MKID_BE('mdhd'), &QTPlayer::readMDHD },
- { MKID_BE('mdia'), &QTPlayer::readDefault },
- { MKID_BE('minf'), &QTPlayer::readDefault },
- { MKID_BE('moov'), &QTPlayer::readMOOV },
- { MKID_BE('mvhd'), &QTPlayer::readMVHD },
- { MKID_BE('smhd'), &QTPlayer::readLeaf },
- { MKID_BE('stbl'), &QTPlayer::readDefault },
- { MKID_BE('stco'), &QTPlayer::readSTCO },
- { MKID_BE('stsc'), &QTPlayer::readSTSC },
- { MKID_BE('stsd'), &QTPlayer::readSTSD },
- { MKID_BE('stss'), &QTPlayer::readSTSS },
- { MKID_BE('stsz'), &QTPlayer::readSTSZ },
- { MKID_BE('stts'), &QTPlayer::readSTTS },
- { MKID_BE('tkhd'), &QTPlayer::readTKHD },
- { MKID_BE('trak'), &QTPlayer::readTRAK },
- { MKID_BE('udta'), &QTPlayer::readLeaf },
- { MKID_BE('vmhd'), &QTPlayer::readLeaf },
- { MKID_BE('cmov'), &QTPlayer::readCMOV },
- { MKID_BE('wave'), &QTPlayer::readWAVE },
- { 0, 0 }
- };
-
- _parseTable = p;
-}
-
-int QTPlayer::readDefault(MOVatom atom) {
- uint32 total_size = 0;
- MOVatom a;
- int err = 0;
-
- a.offset = atom.offset;
-
- while(((total_size + 8) < atom.size) && !_fd->eos() && !err) {
- a.size = atom.size;
- a.type = 0;
-
- if (atom.size >= 8) {
- a.size = _fd->readUint32BE();
- a.type = _fd->readUint32BE();
- }
-
- total_size += 8;
- a.offset += 8;
- debug(4, "type: %08x %.4s sz: %x %x %x", a.type, tag2str(a.type), a.size, atom.size, total_size);
-
- if (a.size == 1) { // 64 bit extended size
- warning("64 bit extended size is not supported in QuickTime");
- return -1;
- }
-
- if (a.size == 0) {
- a.size = atom.size - total_size;
- if (a.size <= 8)
- break;
- }
-
- uint32 i = 0;
-
- for (; _parseTable[i].type != 0 && _parseTable[i].type != a.type; i++)
- // empty;
-
- if (a.size < 8)
- break;
-
- a.size -= 8;
-
- if (_parseTable[i].type == 0) { // skip leaf atoms data
- debug(0, ">>> Skipped [%s]", tag2str(a.type));
-
- _fd->seek(a.size, SEEK_CUR);
- } else {
- uint32 start_pos = _fd->pos();
- err = (this->*_parseTable[i].func)(a);
-
- uint32 left = a.size - _fd->pos() + start_pos;
-
- if (left > 0) // skip garbage at atom end
- _fd->seek(left, SEEK_CUR);
- }
-
- a.offset += a.size;
- total_size += a.size;
- }
-
- if (!err && total_size < atom.size)
- _fd->seek(atom.size - total_size, SEEK_SET);
-
- return err;
-}
-
-int QTPlayer::readLeaf(MOVatom atom) {
- if (atom.size > 1)
- _fd->seek(atom.size, SEEK_SET);
-
- return 0;
-}
-
-int QTPlayer::readMOOV(MOVatom atom) {
- if (readDefault(atom) < 0)
- return -1;
-
- // we parsed the 'moov' atom, we can terminate the parsing as soon as we find the 'mdat'
- // so we don't parse the whole file if over a network
- _foundMOOV = true;
-
- if(_foundMDAT)
- return 1; // found both, just go
-
- return 0; // now go for mdat
-}
-
-int QTPlayer::readCMOV(MOVatom atom) {
-#ifdef USE_ZLIB
- // Read in the dcom atom
- _fd->readUint32BE();
- if (_fd->readUint32BE() != MKID_BE('dcom'))
- return -1;
- if (_fd->readUint32BE() != MKID_BE('zlib')) {
- warning("Unknown cmov compression type");
- return -1;
- }
-
- // Read in the cmvd atom
- uint32 compressedSize = _fd->readUint32BE() - 12;
- if (_fd->readUint32BE() != MKID_BE('cmvd'))
- return -1;
- uint32 uncompressedSize = _fd->readUint32BE();
-
- // Read in data
- byte *compressedData = (byte *)malloc(compressedSize);
- _fd->read(compressedData, compressedSize);
-
- // Create uncompressed stream
- byte *uncompressedData = (byte *)malloc(uncompressedSize);
-
- // Uncompress the data
- unsigned long dstLen = uncompressedSize;
- if (!Common::uncompress(uncompressedData, &dstLen, compressedData, compressedSize)) {
- warning ("Could not uncompress cmov chunk");
- return -1;
- }
-
- // Load data into a new MemoryReadStream and assign _fd to be that
- Common::SeekableReadStream *oldStream = _fd;
- _fd = new Common::MemoryReadStream(uncompressedData, uncompressedSize, DisposeAfterUse::YES);
-
- // Read the contents of the uncompressed data
- MOVatom a = { MKID_BE('moov'), 0, uncompressedSize };
- int err = readDefault(a);
-
- // Assign the file handle back to the original handle
- free(compressedData);
- delete _fd;
- _fd = oldStream;
-
- return err;
-#else
- warning ("zlib not found, cannot read QuickTime cmov atom");
- return -1;
-#endif
-}
-
-int QTPlayer::readMVHD(MOVatom atom) {
- byte version = _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- if (version == 1) {
- warning("QuickTime version 1");
- _fd->readUint32BE(); _fd->readUint32BE();
- _fd->readUint32BE(); _fd->readUint32BE();
- } else {
- _fd->readUint32BE(); // creation time
- _fd->readUint32BE(); // modification time
- }
-
- _timeScale = _fd->readUint32BE(); // time scale
- debug(0, "time scale = %i\n", _timeScale);
-
- // duration
- _duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE();
- _fd->readUint32BE(); // preferred scale
-
- _fd->readUint16BE(); // preferred volume
-
- _fd->seek(10, SEEK_CUR); // reserved
-
- // We only need two values from the movie display matrix. Most of the values are just
- // skipped. xMod and yMod are 16:16 fixed point numbers, the last part of the 3x3 matrix
- // is 2:30.
- uint32 xMod = _fd->readUint32BE();
- _fd->skip(12);
- uint32 yMod = _fd->readUint32BE();
- _fd->skip(16);
-
- if (xMod != yMod)
- error("X and Y resolution modifiers differ");
-
- if (xMod == 0x8000)
- _scaleMode = kScaleHalf;
- else if (xMod == 0x4000)
- _scaleMode = kScaleQuarter;
- else
- _scaleMode = kScaleNormal;
-
- debug(1, "readMVHD(): scaleMode = %d", (int)_scaleMode);
-
- _fd->readUint32BE(); // preview time
- _fd->readUint32BE(); // preview duration
- _fd->readUint32BE(); // poster time
- _fd->readUint32BE(); // selection time
- _fd->readUint32BE(); // selection duration
- _fd->readUint32BE(); // current time
- _fd->readUint32BE(); // next track ID
-
- return 0;
-}
-
-int QTPlayer::readTRAK(MOVatom atom) {
- MOVStreamContext *sc = new MOVStreamContext();
-
- if (!sc)
- return -1;
-
- sc->sample_to_chunk_index = -1;
- sc->codec_type = CODEC_TYPE_MOV_OTHER;
- sc->start_time = 0; // XXX: check
- _streams[_numStreams++] = sc;
-
- return readDefault(atom);
-}
-
-// this atom contains actual media data
-int QTPlayer::readMDAT(MOVatom atom) {
- if (atom.size == 0) // wrong one (MP4)
- return 0;
-
- _foundMDAT = true;
-
- _mdatOffset = atom.offset;
- _mdatSize = atom.size;
-
- if (_foundMOOV)
- return 1; // found both, just go
-
- _fd->seek(atom.size, SEEK_CUR);
-
- return 0; // now go for moov
-}
-
-int QTPlayer::readTKHD(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
- byte version = _fd->readByte();
-
- _fd->readByte(); _fd->readByte();
- _fd->readByte(); // flags
- //
- //MOV_TRACK_ENABLED 0x0001
- //MOV_TRACK_IN_MOVIE 0x0002
- //MOV_TRACK_IN_PREVIEW 0x0004
- //MOV_TRACK_IN_POSTER 0x0008
- //
-
- if (version == 1) {
- _fd->readUint32BE(); _fd->readUint32BE();
- _fd->readUint32BE(); _fd->readUint32BE();
- } else {
- _fd->readUint32BE(); // creation time
- _fd->readUint32BE(); // modification time
- }
-
- /* st->id = */_fd->readUint32BE(); // track id (NOT 0 !)
- _fd->readUint32BE(); // reserved
- //st->start_time = 0; // check
- (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // highlevel (considering edits) duration in movie timebase
- _fd->readUint32BE(); // reserved
- _fd->readUint32BE(); // reserved
-
- _fd->readUint16BE(); // layer
- _fd->readUint16BE(); // alternate group
- _fd->readUint16BE(); // volume
- _fd->readUint16BE(); // reserved
-
- // We only need the two values from the displacement matrix for a track.
- // See readMVHD() for more information.
- uint32 xMod = _fd->readUint32BE();
- _fd->skip(12);
- uint32 yMod = _fd->readUint32BE();
- _fd->skip(16);
-
- if (xMod != yMod)
- error("X and Y resolution modifiers differ");
-
- if (xMod == 0x8000)
- st->scaleMode = kScaleHalf;
- else if (xMod == 0x4000)
- st->scaleMode = kScaleQuarter;
- else
- st->scaleMode = kScaleNormal;
-
- debug(1, "readTKHD(): scaleMode = %d", (int)_scaleMode);
-
- // these are fixed-point, 16:16
- // uint32 tkWidth = _fd->readUint32BE() >> 16; // track width
- // uint32 tkHeight = _fd->readUint32BE() >> 16; // track height
-
- return 0;
-}
-
-// edit list atom
-int QTPlayer::readELST(MOVatom atom) {
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
- uint32 editCount = _streams[_numStreams - 1]->edit_count = _fd->readUint32BE(); // entries
-
- for (uint32 i = 0; i < editCount; i++){
- _fd->readUint32BE(); // Track duration
- _fd->readUint32BE(); // Media time
- _fd->readUint32BE(); // Media rate
- }
-
- debug(0, "track[%i].edit_count = %i", _numStreams - 1, _streams[_numStreams - 1]->edit_count);
-
- if (editCount != 1)
- warning("Multiple edit list entries. Things may go awry");
-
- return 0;
-}
-
-int QTPlayer::readHDLR(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- // component type
- uint32 ctype = _fd->readUint32LE();
- uint32 type = _fd->readUint32BE(); // component subtype
-
- debug(0, "ctype= %s (0x%08lx)", tag2str(ctype), (long)ctype);
- debug(0, "stype= %s", tag2str(type));
-
- if(ctype == MKID_BE('mhlr')) // MOV
- debug(0, "MOV detected");
- else if(ctype == 0) {
- warning("MP4 streams are not supported");
- return -1;
- }
-
- if (type == MKID_BE('vide'))
- st->codec_type = CODEC_TYPE_VIDEO;
- else if (type == MKID_BE('soun'))
- st->codec_type = CODEC_TYPE_AUDIO;
-
- _fd->readUint32BE(); // component manufacture
- _fd->readUint32BE(); // component flags
- _fd->readUint32BE(); // component flags mask
-
- if (atom.size <= 24)
- return 0; // nothing left to read
-
- // .mov: PASCAL string
- byte len = _fd->readByte();
- _fd->seek(len, SEEK_CUR);
-
- _fd->seek(atom.size - (_fd->pos() - atom.offset), SEEK_CUR);
-
- return 0;
-}
-
-int QTPlayer::readMDHD(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
- byte version = _fd->readByte();
-
- if (version > 1)
- return 1; // unsupported
-
- _fd->readByte(); _fd->readByte();
- _fd->readByte(); // flags
-
- if (version == 1) {
- _fd->readUint32BE(); _fd->readUint32BE();
- _fd->readUint32BE(); _fd->readUint32BE();
- } else {
- _fd->readUint32BE(); // creation time
- _fd->readUint32BE(); // modification time
- }
-
- st->time_scale = _fd->readUint32BE();
- st->duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // duration
-
- _fd->readUint16BE(); // language
- _fd->readUint16BE(); // quality
-
- return 0;
-}
-
-int QTPlayer::readSTSD(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- uint32 entries = _fd->readUint32BE();
-
- while (entries--) { //Parsing Sample description table
- MOVatom a = { 0, 0, 0 };
- uint32 start_pos = _fd->pos();
- int size = _fd->readUint32BE(); // size
- uint32 format = _fd->readUint32BE(); // data format
-
- _fd->readUint32BE(); // reserved
- _fd->readUint16BE(); // reserved
- _fd->readUint16BE(); // index
-
- debug(0, "size=%d 4CC= %s codec_type=%d", size, tag2str(format), st->codec_type);
- st->codec_tag = format;
-
- if (st->codec_type == CODEC_TYPE_VIDEO) {
- debug(0, "Video Codec FourCC: \'%s\'", tag2str(format));
-
- _fd->readUint16BE(); // version
- _fd->readUint16BE(); // revision level
- _fd->readUint32BE(); // vendor
- _fd->readUint32BE(); // temporal quality
- _fd->readUint32BE(); // spacial quality
-
- st->width = _fd->readUint16BE(); // width
- st->height = _fd->readUint16BE(); // height
-
- _fd->readUint32BE(); // horiz resolution
- _fd->readUint32BE(); // vert resolution
- _fd->readUint32BE(); // data size, always 0
- uint16 frames_per_sample = _fd->readUint16BE(); // frames per samples
-
- debug(0, "frames/samples = %d", frames_per_sample);
-
- byte codec_name[32];
- _fd->read(codec_name, 32); // codec name, pascal string (FIXME: true for mp4?)
- if (codec_name[0] <= 31) {
- memcpy(st->codec_name, &codec_name[1], codec_name[0]);
- st->codec_name[codec_name[0]] = 0;
- }
-
- st->bits_per_sample = _fd->readUint16BE(); // depth
- st->color_table_id = _fd->readUint16BE(); // colortable id
-
-// These are set in mov_read_stts and might already be set!
-// st->codec->time_base.den = 25;
-// st->codec->time_base.num = 1;
-
-
- // figure out the palette situation
- byte colorDepth = st->bits_per_sample & 0x1F;
- bool colorGreyscale = (st->bits_per_sample & 0x20) != 0;
-
- debug(0, "color depth: %d", colorDepth);
-
- // if the depth is 2, 4, or 8 bpp, file is palettized
- if (colorDepth == 2 || colorDepth == 4 || colorDepth == 8) {
- _dirtyPalette = true;
-
- if (colorGreyscale) {
- debug(0, "Greyscale palette");
-
- // compute the greyscale palette
- uint16 colorCount = 1 << colorDepth;
- int16 colorIndex = 255;
- byte colorDec = 256 / (colorCount - 1);
- for (byte j = 0; j < colorCount; j++) {
- _palette[j * 3] = _palette[j * 3 + 1] = _palette[j * 3 + 2] = colorIndex;
- colorIndex -= colorDec;
- if (colorIndex < 0)
- colorIndex = 0;
- }
- } else if (st->color_table_id & 0x08) {
- // if flag bit 3 is set, use the default palette
- //uint16 colorCount = 1 << colorDepth;
-
- warning("Predefined palette! %dbpp", colorDepth);
-#if 0
- byte *color_table;
- byte r, g, b;
-
- if (colorDepth == 2)
- color_table = ff_qt_default_palette_4;
- else if (colorDepth == 4)
- color_table = ff_qt_default_palette_16;
- else
- color_table = ff_qt_default_palette_256;
-
- for (byte j = 0; j < color_count; j++) {
- r = color_table[j * 4 + 0];
- g = color_table[j * 4 + 1];
- b = color_table[j * 4 + 2];
- _palette_control.palette[j] = (r << 16) | (g << 8) | (b);
- }
-#endif
-
- } else {
- debug(0, "Palette from file");
-
- // load the palette from the file
- uint32 colorStart = _fd->readUint32BE();
- /* uint16 colorCount = */ _fd->readUint16BE();
- uint16 colorEnd = _fd->readUint16BE();
- for (uint32 j = colorStart; j <= colorEnd; j++) {
- // each R, G, or B component is 16 bits;
- // only use the top 8 bits; skip alpha bytes
- // up front
- _fd->readByte();
- _fd->readByte();
- _palette[j * 3] = _fd->readByte();
- _fd->readByte();
- _palette[j * 3 + 1] = _fd->readByte();
- _fd->readByte();
- _palette[j * 3 + 2] = _fd->readByte();
- _fd->readByte();
- }
- }
- st->palettized = true;
- } else
- st->palettized = false;
- } else if (st->codec_type == CODEC_TYPE_AUDIO) {
- debug(0, "Audio Codec FourCC: \'%s\'", tag2str(format));
-
- st->stsd_version = _fd->readUint16BE();
- _fd->readUint16BE(); // revision level
- _fd->readUint32BE(); // vendor
-
- st->channels = _fd->readUint16BE(); // channel count
- st->bits_per_sample = _fd->readUint16BE(); // sample size
- // do we need to force to 16 for AMR ?
-
- // handle specific s8 codec
- _fd->readUint16BE(); // compression id = 0
- _fd->readUint16BE(); // packet size = 0
-
- st->sample_rate = (_fd->readUint32BE() >> 16);
-
- debug(0, "stsd version =%d", st->stsd_version);
- if (st->stsd_version == 0) {
- // Not used, except in special cases. See below.
- st->samples_per_frame = st->bytes_per_frame = 0;
- } else if (st->stsd_version == 1) {
- // Read QT version 1 fields. In version 0 these dont exist.
- st->samples_per_frame = _fd->readUint32BE();
- debug(0, "stsd samples_per_frame =%d", st->samples_per_frame);
- _fd->readUint32BE(); // bytes per packet
- st->bytes_per_frame = _fd->readUint32BE();
- debug(0, "stsd bytes_per_frame =%d", st->bytes_per_frame);
- _fd->readUint32BE(); // bytes per sample
- } else {
- warning("Unsupported QuickTime STSD audio version %d", st->stsd_version);
- return 1;
- }
-
- // Version 0 videos (such as the Riven ones) don't have this set,
- // but we need it later on. Add it in here.
- if (format == MKID_BE('ima4')) {
- st->samples_per_frame = 64;
- st->bytes_per_frame = 34 * st->channels;
- }
- } else {
- // other codec type, just skip (rtp, mp4s, tmcd ...)
- _fd->seek(size - (_fd->pos() - start_pos), SEEK_CUR);
- }
-
- // this will read extra atoms at the end (wave, alac, damr, avcC, SMI ...)
- a.size = size - (_fd->pos() - start_pos);
- if (a.size > 8)
- readDefault(a);
- else if (a.size > 0)
- _fd->seek(a.size, SEEK_CUR);
- }
-
- if (st->codec_type == CODEC_TYPE_AUDIO && st->sample_rate == 0 && st->time_scale > 1)
- st->sample_rate= st->time_scale;
-
- return 0;
-}
-
-int QTPlayer::readSTSC(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->sample_to_chunk_sz = _fd->readUint32BE();
-
- debug(0, "track[%i].stsc.entries = %i", _numStreams - 1, st->sample_to_chunk_sz);
-
- st->sample_to_chunk = new MOVstsc[st->sample_to_chunk_sz];
-
- if (!st->sample_to_chunk)
- return -1;
-
- for (uint32 i = 0; i < st->sample_to_chunk_sz; i++) {
- st->sample_to_chunk[i].first = _fd->readUint32BE();
- st->sample_to_chunk[i].count = _fd->readUint32BE();
- st->sample_to_chunk[i].id = _fd->readUint32BE();
- //printf ("Sample to Chunk[%d]: First = %d, Count = %d\n", i, st->sample_to_chunk[i].first, st->sample_to_chunk[i].count);
- }
-
- return 0;
-}
-
-int QTPlayer::readSTSS(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->keyframe_count = _fd->readUint32BE();
-
- debug(0, "keyframe_count = %d", st->keyframe_count);
-
- st->keyframes = new uint32[st->keyframe_count];
-
- if (!st->keyframes)
- return -1;
-
- for (uint32 i = 0; i < st->keyframe_count; i++) {
- st->keyframes[i] = _fd->readUint32BE();
- debug(6, "keyframes[%d] = %d", i, st->keyframes[i]);
-
- }
- return 0;
-}
-
-int QTPlayer::readSTSZ(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->sample_size = _fd->readUint32BE();
- st->sample_count = _fd->readUint32BE();
-
- debug(5, "sample_size = %d sample_count = %d", st->sample_size, st->sample_count);
-
- if (st->sample_size)
- return 0; // there isn't any table following
-
- st->sample_sizes = new uint32[st->sample_count];
-
- if (!st->sample_sizes)
- return -1;
-
- for(uint32 i = 0; i < st->sample_count; i++) {
- st->sample_sizes[i] = _fd->readUint32BE();
- debug(6, "sample_sizes[%d] = %d", i, st->sample_sizes[i]);
- }
-
- return 0;
-}
-
-static uint32 ff_gcd(uint32 a, uint32 b) {
- if(b) return ff_gcd(b, a%b);
- else return a;
-}
-
-int QTPlayer::readSTTS(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
- uint32 duration = 0;
- uint32 total_sample_count = 0;
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->stts_count = _fd->readUint32BE();
- st->stts_data = new MOVstts[st->stts_count];
-
- debug(0, "track[%i].stts.entries = %i", _numStreams - 1, st->stts_count);
-
- st->time_rate = 0;
-
- for (int32 i = 0; i < st->stts_count; i++) {
- int sample_duration;
- int sample_count;
-
- sample_count = _fd->readUint32BE();
- sample_duration = _fd->readUint32BE();
- st->stts_data[i].count = sample_count;
- st->stts_data[i].duration = sample_duration;
-
- st->time_rate = ff_gcd(st->time_rate, sample_duration);
-
- debug(0, "sample_count=%d, sample_duration=%d", sample_count, sample_duration);
-
- duration += sample_duration * sample_count;
- total_sample_count += sample_count;
- }
-
- st->nb_frames = total_sample_count;
-
- if (duration)
- st->duration = duration;
-
- return 0;
-}
-
-int QTPlayer::readSTCO(MOVatom atom) {
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- _fd->readByte(); // version
- _fd->readByte(); _fd->readByte(); _fd->readByte(); // flags
-
- st->chunk_count = _fd->readUint32BE();
- st->chunk_offsets = new uint32[st->chunk_count];
-
- if (!st->chunk_offsets)
- return -1;
-
- for (uint32 i = 0; i < st->chunk_count; i++) {
- // WORKAROUND/HACK: The offsets in Riven videos (ones inside the Mohawk archives themselves)
- // have offsets relative to the archive and not the video. This is quite nasty. We subtract
- // the initial offset of the stream to get the correct value inside of the stream.
- st->chunk_offsets[i] = _fd->readUint32BE() - _beginOffset;
- }
-
- for (uint32 i = 0; i < _numStreams; i++) {
- MOVStreamContext *sc2 = _streams[i];
-
- if(sc2 && sc2->chunk_offsets){
- uint32 first = sc2->chunk_offsets[0];
- uint32 last = sc2->chunk_offsets[sc2->chunk_count - 1];
-
- if(first >= st->chunk_offsets[st->chunk_count - 1] || last <= st->chunk_offsets[0])
- _ni = 1;
- }
- }
-
- return 0;
-}
-
-int QTPlayer::readWAVE(MOVatom atom) {
- if (_numStreams < 1)
- return 0;
-
- MOVStreamContext *st = _streams[_numStreams - 1];
-
- if (atom.size > (1 << 30))
- return -1;
-
- if (st->codec_tag == MKID_BE('QDM2')) // Read extradata for QDM2
- st->extradata = _fd->readStream(atom.size - 8);
- else if (atom.size > 8)
- return readDefault(atom);
- else
- _fd->skip(atom.size);
-
- return 0;
-}
-
-void QTPlayer::close() {
- stopAudio();
-
- delete _videoCodec; _videoCodec = 0;
-
- for (uint32 i = 0; i < _numStreams; i++)
- delete _streams[i];
-
- delete _fd;
-
- if (_scaledSurface) {
- _scaledSurface->free();
- delete _scaledSurface;
- _scaledSurface = 0;
- }
-
- // The audio stream is deleted automatically
- _audStream = NULL;
-
- Graphics::VideoDecoder::reset();
-}
-
-Common::SeekableReadStream *QTPlayer::getNextFramePacket() {
- if (_videoStreamIndex < 0)
- return NULL;
-
- // First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for.
- int32 totalSampleCount = 0;
- int32 sampleInChunk = 0;
- int32 actualChunk = -1;
-
- for (uint32 i = 0; i < _streams[_videoStreamIndex]->chunk_count; i++) {
- int32 sampleToChunkIndex = -1;
-
- for (uint32 j = 0; j < _streams[_videoStreamIndex]->sample_to_chunk_sz; j++)
- if (i >= _streams[_videoStreamIndex]->sample_to_chunk[j].first - 1)
- sampleToChunkIndex = j;
-
- if (sampleToChunkIndex < 0)
- error("This chunk (%d) is imaginary", sampleToChunkIndex);
-
- totalSampleCount += _streams[_videoStreamIndex]->sample_to_chunk[sampleToChunkIndex].count;
-
- if (totalSampleCount > getCurFrame()) {
- actualChunk = i;
- sampleInChunk = _streams[_videoStreamIndex]->sample_to_chunk[sampleToChunkIndex].count - totalSampleCount + getCurFrame();
- break;
- }
- }
-
- if (actualChunk < 0) {
- warning ("Could not find data for frame %d", getCurFrame());
- return NULL;
- }
-
- // Next seek to that frame
- _fd->seek(_streams[_videoStreamIndex]->chunk_offsets[actualChunk]);
-
- // Then, if the chunk holds more than one frame, seek to where the frame we want is located
- for (int32 i = getCurFrame() - sampleInChunk; i < getCurFrame(); i++) {
- if (_streams[_videoStreamIndex]->sample_size != 0)
- _fd->skip(_streams[_videoStreamIndex]->sample_size);
- else
- _fd->skip(_streams[_videoStreamIndex]->sample_sizes[i]);
- }
-
- // Finally, read in the raw data for the frame
- //printf ("Frame Data[%d]: Offset = %d, Size = %d\n", getCurFrame(), _fd->pos(), _streams[_videoStreamIndex]->sample_sizes[getCurFrame()]);
-
- if (_streams[_videoStreamIndex]->sample_size != 0)
- return _fd->readStream(_streams[_videoStreamIndex]->sample_size);
-
- return _fd->readStream(_streams[_videoStreamIndex]->sample_sizes[getCurFrame()]);
-}
-
-bool QTPlayer::checkAudioCodecSupport(uint32 tag) {
- // Check if the codec is a supported codec
- if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4') || tag == MKID_BE('QDM2'))
- return true;
-
- warning("Audio Codec Not Supported: \'%s\'", tag2str(tag));
-
- return false;
-}
-
-Audio::AudioStream *QTPlayer::createAudioStream(Common::SeekableReadStream *stream) {
- if (!stream || _audioStreamIndex < 0)
- return NULL;
-
- if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('twos') || _streams[_audioStreamIndex]->codec_tag == MKID_BE('raw ')) {
- // Fortunately, most of the audio used in Myst videos is raw...
- uint16 flags = 0;
- if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('raw '))
- flags |= Audio::FLAG_UNSIGNED;
- if (_streams[_audioStreamIndex]->channels == 2)
- flags |= Audio::FLAG_STEREO;
- if (_streams[_audioStreamIndex]->bits_per_sample == 16)
- flags |= Audio::FLAG_16BITS;
- uint32 dataSize = stream->size();
- byte *data = (byte *)malloc(dataSize);
- stream->read(data, dataSize);
- delete stream;
- return Audio::makeRawStream(data, dataSize, _streams[_audioStreamIndex]->sample_rate, flags);
- } else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('ima4')) {
- // Riven uses this codec (as do some Myst ME videos)
- return Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMApple, _streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels, 34);
- } else if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('QDM2')) {
- // Several Myst ME videos use this codec
- return new QDM2Stream(stream, _streams[_audioStreamIndex]->extradata);
- }
-
- error("Unsupported audio codec");
-
- return NULL;
-}
-
-void QTPlayer::updateAudioBuffer() {
- if (!_audStream)
- return;
-
- // Keep two streams in buffer so that when the first ends, it goes right into the next
- for (; _audStream->numQueuedStreams() < 2 && _curAudioChunk < _streams[_audioStreamIndex]->chunk_count; _curAudioChunk++) {
- Common::MemoryWriteStreamDynamic *wStream = new Common::MemoryWriteStreamDynamic();
-
- _fd->seek(_streams[_audioStreamIndex]->chunk_offsets[_curAudioChunk]);
-
- // First, we have to get the sample count
- uint32 sampleCount = 0;
- for (uint32 j = 0; j < _streams[_audioStreamIndex]->sample_to_chunk_sz; j++)
- if (_curAudioChunk >= (_streams[_audioStreamIndex]->sample_to_chunk[j].first - 1))
- sampleCount = _streams[_audioStreamIndex]->sample_to_chunk[j].count;
- assert(sampleCount);
-
- // Then calculate the right sizes
- while (sampleCount > 0) {
- uint32 samples = 0, size = 0;
-
- if (_streams[_audioStreamIndex]->samples_per_frame >= 160) {
- samples = _streams[_audioStreamIndex]->samples_per_frame;
- size = _streams[_audioStreamIndex]->bytes_per_frame;
- } else if (_streams[_audioStreamIndex]->samples_per_frame > 1) {
- samples = MIN<uint32>((1024 / _streams[_audioStreamIndex]->samples_per_frame) * _streams[_audioStreamIndex]->samples_per_frame, sampleCount);
- size = (samples / _streams[_audioStreamIndex]->samples_per_frame) * _streams[_audioStreamIndex]->bytes_per_frame;
- } else {
- samples = MIN<uint32>(1024, sampleCount);
- size = samples * _streams[_audioStreamIndex]->sample_size;
- }
-
- // Now, we read in the data for this data and output it
- byte *data = (byte *)malloc(size);
- _fd->read(data, size);
- wStream->write(data, size);
- free(data);
- sampleCount -= samples;
- }
-
- // Now queue the buffer
- _audStream->queueAudioStream(createAudioStream(new Common::MemoryReadStream(wStream->getData(), wStream->size(), DisposeAfterUse::YES)));
- delete wStream;
- }
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qt_player.h b/engines/mohawk/video/qt_player.h
deleted file mode 100644
index 6657d3edba..0000000000
--- a/engines/mohawk/video/qt_player.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-//
-// Heavily based on ffmpeg code.
-//
-// Copyright (c) 2001 Fabrice Bellard.
-// First version by Francois Revol revol@free.fr
-// Seek function by Gael Chardon gael.dev@4now.net
-//
-
-#ifndef MOHAWK_QT_PLAYER_H
-#define MOHAWK_QT_PLAYER_H
-
-#include "common/scummsys.h"
-#include "common/queue.h"
-
-#include "graphics/video/video_decoder.h"
-#include "graphics/video/codecs/codec.h"
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-
-namespace Common {
- class File;
-}
-
-namespace Mohawk {
-
-enum ScaleMode {
- kScaleNormal = 1,
- kScaleHalf = 2,
- kScaleQuarter = 4
-};
-
-class QTPlayer : public Graphics::RewindableVideoDecoder {
-public:
- QTPlayer();
- virtual ~QTPlayer();
-
- /**
- * Returns the width of the video
- * @return the width of the video
- */
- uint16 getWidth() const;
-
- /**
- * Returns the height of the video
- * @return the height of the video
- */
- uint16 getHeight() const;
-
- /**
- * Returns the amount of frames in the video
- * @return the amount of frames in the video
- */
- uint32 getFrameCount() const;
-
- /**
- * Load a QuickTime video file from a SeekableReadStream
- * @param stream the stream to load
- */
- bool load(Common::SeekableReadStream &stream);
-
- /**
- * Close a QuickTime encoded video file
- */
- void close();
-
- /**
- * Returns the palette of the video
- * @return the palette of the video
- */
- byte *getPalette() { _dirtyPalette = false; return _palette; }
- bool hasDirtyPalette() const { return _dirtyPalette; }
-
- /**
- * Set the beginning offset of the video so we can modify the offsets in the stco
- * atom of videos inside the Mohawk archives
- * @param the beginning offset of the video
- */
- void setChunkBeginOffset(uint32 offset) { _beginOffset = offset; }
-
- bool isVideoLoaded() const { return _fd != 0; }
- Graphics::Surface *decodeNextFrame();
- bool needsUpdate() const;
- bool endOfVideo() const;
- uint32 getElapsedTime() const;
- uint32 getTimeToNextFrame() const;
- Graphics::PixelFormat getPixelFormat() const;
-
- // RewindableVideoDecoder API
- void rewind();
-
- // TODO: This audio function need to be removed from the public and/or added to
- // the VideoDecoder API directly. I plan on replacing this function with something
- // that can figure out how much audio is needed instead of constantly keeping two
- // chunks in memory.
- void updateAudioBuffer();
-
-protected:
- // This is the file handle from which data is read from. It can be the actual file handle or a decompressed stream.
- Common::SeekableReadStream *_fd;
-
- struct MOVatom {
- uint32 type;
- uint32 offset;
- uint32 size;
- };
-
- struct ParseTable {
- uint32 type;
- int (QTPlayer::*func)(MOVatom atom);
- };
-
- struct MOVstts {
- int count;
- int duration;
- };
-
- struct MOVstsc {
- uint32 first;
- uint32 count;
- uint32 id;
- };
-
- enum CodecType {
- CODEC_TYPE_MOV_OTHER,
- CODEC_TYPE_VIDEO,
- CODEC_TYPE_AUDIO
- };
-
- struct MOVStreamContext {
- MOVStreamContext() { memset(this, 0, sizeof(MOVStreamContext)); }
- ~MOVStreamContext() {
- delete[] chunk_offsets;
- delete[] stts_data;
- delete[] ctts_data;
- delete[] sample_to_chunk;
- delete[] sample_sizes;
- delete[] keyframes;
- delete extradata;
- }
-
- int ffindex; /* the ffmpeg stream id */
- int is_ff_stream; /* Is this stream presented to ffmpeg ? i.e. is this an audio or video stream ? */
- uint32 next_chunk;
- uint32 chunk_count;
- uint32 *chunk_offsets;
- int stts_count;
- MOVstts *stts_data;
- int ctts_count;
- MOVstts *ctts_data;
- int edit_count; /* number of 'edit' (elst atom) */
- uint32 sample_to_chunk_sz;
- MOVstsc *sample_to_chunk;
- int32 sample_to_chunk_index;
- int sample_to_time_index;
- uint32 sample_to_time_sample;
- uint32 sample_to_time_time;
- int sample_to_ctime_index;
- int sample_to_ctime_sample;
- uint32 sample_size;
- uint32 sample_count;
- uint32 *sample_sizes;
- uint32 keyframe_count;
- uint32 *keyframes;
- int32 time_scale;
- int time_rate;
- uint32 current_sample;
- uint32 left_in_chunk; /* how many samples before next chunk */
-
- uint16 width;
- uint16 height;
- int codec_type;
- uint32 codec_tag;
- char codec_name[32];
- uint16 bits_per_sample;
- uint16 color_table_id;
- bool palettized;
- Common::SeekableReadStream *extradata;
-
- uint16 stsd_version;
- uint16 channels;
- uint16 sample_rate;
- uint32 samples_per_frame;
- uint32 bytes_per_frame;
-
- uint32 nb_frames;
- uint32 duration;
- uint32 start_time;
- ScaleMode scaleMode;
- };
-
- const ParseTable *_parseTable;
- bool _foundMOOV;
- bool _foundMDAT;
- uint32 _timeScale;
- uint32 _duration;
- uint32 _mdatOffset;
- uint32 _mdatSize;
- uint32 _next_chunk_offset;
- MOVStreamContext *_partial;
- uint32 _numStreams;
- int _ni;
- ScaleMode _scaleMode;
- MOVStreamContext *_streams[20];
- byte _palette[256 * 3];
- bool _dirtyPalette;
- uint32 _beginOffset;
-
- void initParseTable();
- Audio::AudioStream *createAudioStream(Common::SeekableReadStream *stream);
- bool checkAudioCodecSupport(uint32 tag);
- Common::SeekableReadStream *getNextFramePacket();
- uint32 getFrameDuration();
- uint32 getCodecTag();
- byte getBitsPerPixel();
-
- Audio::QueuingAudioStream *_audStream;
- void startAudio();
- void stopAudio();
- int8 _audioStreamIndex;
- uint _curAudioChunk;
- Audio::SoundHandle _audHandle;
-
- Graphics::Codec *createCodec(uint32 codecTag, byte bitsPerPixel);
- Graphics::Codec *_videoCodec;
- uint32 _nextFrameStartTime;
- int8 _videoStreamIndex;
-
- Graphics::Surface *_scaledSurface;
- Graphics::Surface *scaleSurface(Graphics::Surface *frame);
- ScaleMode getScaleMode() const;
-
- void pauseVideoIntern(bool pause);
-
- int readDefault(MOVatom atom);
- int readLeaf(MOVatom atom);
- int readELST(MOVatom atom);
- int readHDLR(MOVatom atom);
- int readMDAT(MOVatom atom);
- int readMDHD(MOVatom atom);
- int readMOOV(MOVatom atom);
- int readMVHD(MOVatom atom);
- int readTKHD(MOVatom atom);
- int readTRAK(MOVatom atom);
- int readSTCO(MOVatom atom);
- int readSTSC(MOVatom atom);
- int readSTSD(MOVatom atom);
- int readSTSS(MOVatom atom);
- int readSTSZ(MOVatom atom);
- int readSTTS(MOVatom atom);
- int readCMOV(MOVatom atom);
- int readWAVE(MOVatom atom);
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/qtrle.cpp b/engines/mohawk/video/qtrle.cpp
deleted file mode 100644
index c06dbefcb3..0000000000
--- a/engines/mohawk/video/qtrle.cpp
+++ /dev/null
@@ -1,420 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-// QuickTime RLE Decoder
-// Based off ffmpeg's QuickTime RLE decoder (written by Mike Melanson)
-
-#include "mohawk/video/qtrle.h"
-
-#include "common/scummsys.h"
-#include "common/stream.h"
-#include "common/system.h"
-#include "graphics/colormasks.h"
-#include "graphics/surface.h"
-
-namespace Mohawk {
-
-QTRLEDecoder::QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel) : Graphics::Codec() {
- _bitsPerPixel = bitsPerPixel;
- _pixelFormat = g_system->getScreenFormat();
-
- // We need to increase the surface size to a multiple of 4
- uint16 wMod = width % 4;
- if(wMod != 0)
- width += 4 - wMod;
-
- debug(2, "QTRLE corrected width: %d", width);
-
- _surface = new Graphics::Surface();
- _surface->create(width, height, _bitsPerPixel <= 8 ? 1 : _pixelFormat.bytesPerPixel);
-}
-
-#define CHECK_STREAM_PTR(n) \
- if ((stream->pos() + n) > stream->size()) { \
- warning ("Problem: stream out of bounds (%d >= %d)", stream->pos() + n, stream->size()); \
- return; \
- }
-
-#define CHECK_PIXEL_PTR(n) \
- if ((int32)pixelPtr + n > _surface->w * _surface->h) { \
- warning ("Problem: pixel ptr = %d, pixel limit = %d", pixelPtr + n, _surface->w * _surface->h); \
- return; \
- } \
-
-void QTRLEDecoder::decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- byte *rgb = (byte *)_surface->pixels;
-
- while (linesToChange) {
- CHECK_STREAM_PTR(2);
- byte skip = stream->readByte();
- int8 rleCode = stream->readSByte();
-
- if (rleCode == 0)
- break;
-
- if (skip & 0x80) {
- linesToChange--;
- rowPtr += _surface->w;
- pixelPtr = rowPtr + 2 * (skip & 0x7f);
- } else
- pixelPtr += 2 * skip;
-
- if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
- // get the next 2 bytes from the stream, treat them as groups of 8 pixels, and output them rleCode times */
- CHECK_STREAM_PTR(2);
- byte pi0 = stream->readByte();
- byte pi1 = stream->readByte();
- CHECK_PIXEL_PTR(rleCode * 2);
-
- while (rleCode--) {
- rgb[pixelPtr++] = pi0;
- rgb[pixelPtr++] = pi1;
- }
- } else {
- // copy the same pixel directly to output 2 times
- rleCode *= 2;
- CHECK_STREAM_PTR(rleCode);
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--)
- rgb[pixelPtr++] = stream->readByte();
- }
- }
-}
-
-void QTRLEDecoder::decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp) {
- uint32 pixelPtr = 0;
- byte *rgb = (byte *)_surface->pixels;
- byte numPixels = (bpp == 4) ? 8 : 16;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + (numPixels * (stream->readByte() - 1));
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += (numPixels * (stream->readByte() - 1));
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
-
- // get the next 4 bytes from the stream, treat them as palette indices, and output them rleCode times */
- CHECK_STREAM_PTR(4);
-
- byte pi[16]; // 16 palette indices
-
- for (int8 i = numPixels - 1; i >= 0; i--) {
- pi[numPixels - 1 - i] = (stream->readByte() >> ((i * bpp) & 0x07)) & ((1 << bpp) - 1);
-
- // FIXME: Is this right?
- //stream_ptr += ((i & ((num_pixels>>2)-1)) == 0);
- if ((i & ((numPixels >> 2) - 1)) == 0)
- stream->readByte();
- }
-
- CHECK_PIXEL_PTR(rleCode * numPixels);
-
- while (rleCode--)
- for (byte i = 0; i < numPixels; i++)
- rgb[pixelPtr++] = pi[i];
- } else {
- // copy the same pixel directly to output 4 times
- rleCode *= 4;
- CHECK_STREAM_PTR(rleCode);
- CHECK_PIXEL_PTR(rleCode * (numPixels >> 2));
-
- while (rleCode--) {
- byte temp = stream->readByte();
- if (bpp == 4) {
- rgb[pixelPtr++] = (temp >> 4) & 0x0f;
- rgb[pixelPtr++] = temp & 0x0f;
- } else {
- rgb[pixelPtr++] = (temp >> 6) & 0x03;
- rgb[pixelPtr++] = (temp >> 4) & 0x03;
- rgb[pixelPtr++] = (temp >> 2) & 0x03;
- rgb[pixelPtr++] = temp & 0x03;
- }
- }
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-void QTRLEDecoder::decode8(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- byte *rgb = (byte *)_surface->pixels;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + 4 * (stream->readByte() - 1);
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += 4 * (stream->readByte() - 1);
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
-
- // get the next 4 bytes from the stream, treat them as palette indices, and output them rleCode times
- CHECK_STREAM_PTR(4);
-
- byte pi[4]; // 4 palette indexes
-
- for (byte i = 0; i < 4; i++)
- pi[i] = stream->readByte();
-
- CHECK_PIXEL_PTR(rleCode * 4);
-
- while (rleCode--)
- for (byte i = 0; i < 4; i++)
- rgb[pixelPtr++] = pi[i];
- } else {
- // copy the same pixel directly to output 4 times
- rleCode *= 4;
- CHECK_STREAM_PTR(rleCode);
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--)
- rgb[pixelPtr++] = stream->readByte();
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-void QTRLEDecoder::decode16(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- OverlayColor *rgb = (OverlayColor *)_surface->pixels;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + stream->readByte() - 1;
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += stream->readByte() - 1;
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
- CHECK_STREAM_PTR(2);
-
- uint16 rgb16 = stream->readUint16BE();
-
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--) {
- // Convert from RGB555 to the format specified by the Overlay
- byte r = 0, g = 0, b = 0;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(rgb16, r, g, b);
- rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
- }
- } else {
- CHECK_STREAM_PTR(rleCode * 2);
- CHECK_PIXEL_PTR(rleCode);
-
- // copy pixels directly to output
- while (rleCode--) {
- uint16 rgb16 = stream->readUint16BE();
-
- // Convert from RGB555 to the format specified by the Overlay
- byte r = 0, g = 0, b = 0;
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(rgb16, r, g, b);
- rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
- }
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-void QTRLEDecoder::decode24(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- OverlayColor *rgb = (OverlayColor *)_surface->pixels;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + stream->readByte() - 1;
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += stream->readByte() - 1;
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
-
- CHECK_STREAM_PTR(3);
-
- byte r = stream->readByte();
- byte g = stream->readByte();
- byte b = stream->readByte();
-
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--)
- rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
- } else {
- CHECK_STREAM_PTR(rleCode * 3);
- CHECK_PIXEL_PTR(rleCode);
-
- // copy pixels directly to output
- while (rleCode--) {
- byte r = stream->readByte();
- byte g = stream->readByte();
- byte b = stream->readByte();
- rgb[pixelPtr++] = _pixelFormat.RGBToColor(r, g, b);
- }
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-void QTRLEDecoder::decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange) {
- uint32 pixelPtr = 0;
- OverlayColor *rgb = (OverlayColor *)_surface->pixels;
-
- while (linesToChange--) {
- CHECK_STREAM_PTR(2);
- pixelPtr = rowPtr + stream->readByte() - 1;
-
- for (int8 rleCode = stream->readSByte(); rleCode != -1; rleCode = stream->readSByte()) {
- if (rleCode == 0) {
- // there's another skip code in the stream
- CHECK_STREAM_PTR(1);
- pixelPtr += stream->readByte() - 1;
- } else if (rleCode < 0) {
- // decode the run length code
- rleCode = -rleCode;
-
- CHECK_STREAM_PTR(4);
-
- byte a = stream->readByte();
- byte r = stream->readByte();
- byte g = stream->readByte();
- byte b = stream->readByte();
-
- CHECK_PIXEL_PTR(rleCode);
-
- while (rleCode--)
- rgb[pixelPtr++] = _pixelFormat.ARGBToColor(a, r, g, b);
- } else {
- CHECK_STREAM_PTR(rleCode * 4);
- CHECK_PIXEL_PTR(rleCode);
-
- // copy pixels directly to output
- while (rleCode--) {
- byte a = stream->readByte();
- byte r = stream->readByte();
- byte g = stream->readByte();
- byte b = stream->readByte();
- rgb[pixelPtr++] = _pixelFormat.ARGBToColor(a, r, g, b);
- }
- }
- }
-
- rowPtr += _surface->w;
- }
-}
-
-Graphics::Surface *QTRLEDecoder::decodeImage(Common::SeekableReadStream *stream) {
- uint16 start_line = 0;
- uint16 height = _surface->h;
-
- // check if this frame is even supposed to change
- if (stream->size() < 8)
- return _surface;
-
- // start after the chunk size
- stream->readUint32BE();
-
- // fetch the header
- uint16 header = stream->readUint16BE();
-
- // if a header is present, fetch additional decoding parameters
- if (header & 8) {
- if(stream->size() < 14)
- return _surface;
- start_line = stream->readUint16BE();
- stream->readUint16BE(); // Unknown
- height = stream->readUint16BE();
- stream->readUint16BE(); // Unknown
- }
-
- uint32 row_ptr = _surface->w * start_line;
-
- switch (_bitsPerPixel) {
- case 1:
- case 33:
- decode1(stream, row_ptr, height);
- break;
- case 2:
- case 34:
- decode2_4(stream, row_ptr, height, 2);
- break;
- case 4:
- case 36:
- decode2_4(stream, row_ptr, height, 4);
- break;
- case 8:
- case 40:
- decode8(stream, row_ptr, height);
- break;
- case 16:
- decode16(stream, row_ptr, height);
- break;
- case 24:
- decode24(stream, row_ptr, height);
- break;
- case 32:
- decode32(stream, row_ptr, height);
- break;
- default:
- error ("Unsupported bits per pixel %d", _bitsPerPixel);
- }
-
- return _surface;
-}
-
-QTRLEDecoder::~QTRLEDecoder() {
- _surface->free();
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/qtrle.h b/engines/mohawk/video/qtrle.h
deleted file mode 100644
index 2832bd6b24..0000000000
--- a/engines/mohawk/video/qtrle.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_QTRLE_H
-#define MOHAWK_QTRLE_H
-
-#include "graphics/pixelformat.h"
-#include "graphics/video/codecs/codec.h"
-
-namespace Mohawk {
-
-class QTRLEDecoder : public Graphics::Codec {
-public:
- QTRLEDecoder(uint16 width, uint16 height, byte bitsPerPixel);
- ~QTRLEDecoder();
-
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
- Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
-
-private:
- byte _bitsPerPixel;
-
- Graphics::Surface *_surface;
- Graphics::PixelFormat _pixelFormat;
-
- void decode1(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
- void decode2_4(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange, byte bpp);
- void decode8(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
- void decode16(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
- void decode24(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
- void decode32(Common::SeekableReadStream *stream, uint32 rowPtr, uint32 linesToChange);
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/rpza.cpp b/engines/mohawk/video/rpza.cpp
deleted file mode 100644
index f48c055ae2..0000000000
--- a/engines/mohawk/video/rpza.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
- // Based off ffmpeg's RPZA decoder
-
-#include "mohawk/video/rpza.h"
-
-#include "common/system.h"
-#include "graphics/colormasks.h"
-
-namespace Mohawk {
-
-RPZADecoder::RPZADecoder(uint16 width, uint16 height) : Graphics::Codec() {
- _pixelFormat = g_system->getScreenFormat();
-
- // We need to increase the surface size to a multiple of 4
- uint16 wMod = width % 4;
- if(wMod != 0)
- width += 4 - wMod;
-
- debug(2, "RPZA corrected width: %d", width);
-
- _surface = new Graphics::Surface();
- _surface->create(width, height, _pixelFormat.bytesPerPixel);
-}
-
-#define ADVANCE_BLOCK() \
- pixelPtr += 4; \
- if (pixelPtr >= _surface->w) { \
- pixelPtr = 0; \
- rowPtr += _surface->w * 4; \
- } \
- totalBlocks--; \
- if (totalBlocks < 0) \
- error("block counter just went negative (this should not happen)") \
-
-// Convert from RGB555 to the format specified by the screen
-#define PUT_PIXEL(color) \
- if ((int32)blockPtr < _surface->w * _surface->h) { \
- byte r = 0, g = 0, b = 0; \
- Graphics::colorToRGB<Graphics::ColorMasks<555> >(color, r, g, b); \
- if (_pixelFormat.bytesPerPixel == 2) \
- *((uint16 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \
- else \
- *((uint32 *)_surface->pixels + blockPtr) = _pixelFormat.RGBToColor(r, g, b); \
- } \
- blockPtr++
-
-Graphics::Surface *RPZADecoder::decodeImage(Common::SeekableReadStream *stream) {
- uint16 colorA = 0, colorB = 0;
- uint16 color4[4];
-
- uint32 rowPtr = 0;
- uint32 pixelPtr = 0;
- uint32 blockPtr = 0;
- uint32 rowInc = _surface->w - 4;
- uint16 ta;
- uint16 tb;
-
- // First byte is always 0xe1. Warn if it's different
- byte firstByte = stream->readByte();
- if (firstByte != 0xe1)
- warning("First RPZA chunk byte is 0x%02x instead of 0xe1", firstByte);
-
- // Get chunk size, ingnoring first byte
- uint32 chunkSize = stream->readUint16BE() << 8;
- chunkSize += stream->readByte();
-
- // If length mismatch use size from MOV file and try to decode anyway
- if (chunkSize != (uint32)stream->size()) {
- warning("MOV chunk size != encoded chunk size; using MOV chunk size");
- chunkSize = stream->size();
- }
-
- // Number of 4x4 blocks in frame
- int32 totalBlocks = ((_surface->w + 3) / 4) * ((_surface->h + 3) / 4);
-
- // Process chunk data
- while ((uint32)stream->pos() < chunkSize) {
- byte opcode = stream->readByte(); // Get opcode
- byte numBlocks = (opcode & 0x1f) + 1; // Extract block counter from opcode
-
- // If opcode MSbit is 0, we need more data to decide what to do
- if ((opcode & 0x80) == 0) {
- colorA = (opcode << 8) | stream->readByte();
- opcode = 0;
- if (stream->readByte() & 0x80) {
- // Must behave as opcode 110xxxxx, using colorA computed
- // above. Use fake opcode 0x20 to enter switch block at
- // the right place
- opcode = 0x20;
- numBlocks = 1;
- }
- stream->seek(-1, SEEK_CUR);
- }
-
- switch (opcode & 0xe0) {
- case 0x80: // Skip blocks
- while (numBlocks--) {
- ADVANCE_BLOCK();
- }
- break;
- case 0xa0: // Fill blocks with one color
- colorA = stream->readUint16BE();
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
- for (byte pixel_x = 0; pixel_x < 4; pixel_x++) {
- PUT_PIXEL(colorA);
- }
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // Fill blocks with 4 colors
- case 0xc0:
- colorA = stream->readUint16BE();
- case 0x20:
- colorB = stream->readUint16BE();
-
- // Sort out the colors
- color4[0] = colorB;
- color4[1] = 0;
- color4[2] = 0;
- color4[3] = colorA;
-
- // Red components
- ta = (colorA >> 10) & 0x1F;
- tb = (colorB >> 10) & 0x1F;
- color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10;
- color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10;
-
- // Green components
- ta = (colorA >> 5) & 0x1F;
- tb = (colorB >> 5) & 0x1F;
- color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5;
- color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5;
-
- // Blue components
- ta = colorA & 0x1F;
- tb = colorB & 0x1F;
- color4[1] |= ((11 * ta + 21 * tb) >> 5);
- color4[2] |= ((21 * ta + 11 * tb) >> 5);
-
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
- byte index = stream->readByte();
- for (byte pixel_x = 0; pixel_x < 4; pixel_x++){
- byte idx = (index >> (2 * (3 - pixel_x))) & 0x03;
- PUT_PIXEL(color4[idx]);
- }
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // Fill block with 16 colors
- case 0x00:
- blockPtr = rowPtr + pixelPtr;
- for (byte pixel_y = 0; pixel_y < 4; pixel_y++) {
- for (byte pixel_x = 0; pixel_x < 4; pixel_x++){
- // We already have color of upper left pixel
- if (pixel_y != 0 || pixel_x != 0)
- colorA = stream->readUint16BE();
-
- PUT_PIXEL(colorA);
- }
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- break;
-
- // Unknown opcode
- default:
- error("Unknown opcode %02x in rpza chunk", opcode);
- }
- }
-
- return _surface;
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/rpza.h b/engines/mohawk/video/rpza.h
deleted file mode 100644
index c6d0ada6f5..0000000000
--- a/engines/mohawk/video/rpza.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_RPZA_H
-#define MOHAWK_RPZA_H
-
-#include "graphics/pixelformat.h"
-#include "graphics/video/codecs/codec.h"
-
-namespace Mohawk {
-
-class RPZADecoder : public Graphics::Codec {
-public:
- RPZADecoder(uint16 width, uint16 height);
- ~RPZADecoder() { delete _surface; }
-
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
- Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
-
-private:
- Graphics::Surface *_surface;
- Graphics::PixelFormat _pixelFormat;
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/smc.cpp b/engines/mohawk/video/smc.cpp
deleted file mode 100644
index 4a0d16dfcc..0000000000
--- a/engines/mohawk/video/smc.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-// Based off ffmpeg's SMC decoder
-
-#include "mohawk/video/smc.h"
-
-namespace Mohawk {
-
-#define GET_BLOCK_COUNT() \
- (opcode & 0x10) ? (1 + stream->readByte()) : 1 + (opcode & 0x0F);
-
-#define ADVANCE_BLOCK() \
-{ \
- pixelPtr += 4; \
- if (pixelPtr >= _surface->w) { \
- pixelPtr = 0; \
- rowPtr += _surface->w * 4; \
- } \
- totalBlocks--; \
- if (totalBlocks < 0) { \
- warning("block counter just went negative (this should not happen)"); \
- return _surface; \
- } \
-}
-
-SMCDecoder::SMCDecoder(uint16 width, uint16 height) {
- _surface = new Graphics::Surface();
- _surface->create(width, height, 1);
-}
-
-Graphics::Surface *SMCDecoder::decodeImage(Common::SeekableReadStream *stream) {
- byte *pixels = (byte *)_surface->pixels;
-
- uint32 numBlocks = 0;
- uint32 colorFlags = 0;
- uint32 colorFlagsA = 0;
- uint32 colorFlagsB = 0;
-
- const uint16 rowInc = _surface->w - 4;
- int32 rowPtr = 0;
- int32 pixelPtr = 0;
- uint32 blockPtr = 0;
- uint32 prevBlockPtr = 0;
- uint32 prevBlockPtr1 = 0, prevBlockPtr2 = 0;
- byte prevBlockFlag = false;
- byte pixel = 0;
-
- uint32 colorPairIndex = 0;
- uint32 colorQuadIndex = 0;
- uint32 colorOctetIndex = 0;
- uint32 colorTableIndex = 0; // indices to color pair, quad, or octet tables
-
- int32 chunkSize = stream->readUint32BE() & 0x00FFFFFF;
- if (chunkSize != stream->size())
- warning("MOV chunk size != SMC chunk size (%d != %d); ignoring SMC chunk size", chunkSize, stream->size());
-
- int32 totalBlocks = ((_surface->w + 3) / 4) * ((_surface->h + 3) / 4);
-
- // traverse through the blocks
- while (totalBlocks != 0) {
- // sanity checks
-
- // make sure stream ptr hasn't gone out of bounds
- if (stream->pos() > stream->size()) {
- warning("SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)", stream->pos(), stream->size());
- return _surface;
- }
-
- // make sure the row pointer hasn't gone wild
- if (rowPtr >= _surface->w * _surface->h) {
- warning("SMC decoder just went out of bounds (row ptr = %d, size = %d)", rowPtr, _surface->w * _surface->h);
- return _surface;
- }
-
- byte opcode = stream->readByte();
-
- switch (opcode & 0xF0) {
- // skip n blocks
- case 0x00:
- case 0x10:
- numBlocks = GET_BLOCK_COUNT();
- while (numBlocks--) {
- ADVANCE_BLOCK();
- }
- break;
-
- // repeat last block n times
- case 0x20:
- case 0x30:
- numBlocks = GET_BLOCK_COUNT();
-
- // sanity check
- if (rowPtr == 0 && pixelPtr == 0) {
- warning("encountered repeat block opcode (%02X) but no blocks rendered yet", opcode & 0xF0);
- break;
- }
-
- // figure out where the previous block started
- if (pixelPtr == 0)
- prevBlockPtr1 = (rowPtr - _surface->w * 4) + _surface->w - 4;
- else
- prevBlockPtr1 = rowPtr + pixelPtr - 4;
-
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- prevBlockPtr = prevBlockPtr1;
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++)
- pixels[blockPtr++] = pixels[prevBlockPtr++];
- blockPtr += rowInc;
- prevBlockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // repeat previous pair of blocks n times
- case 0x40:
- case 0x50:
- numBlocks = GET_BLOCK_COUNT();
- numBlocks *= 2;
-
- // sanity check
- if (rowPtr == 0 && pixelPtr < 2 * 4) {
- warning("encountered repeat block opcode (%02X) but not enough blocks rendered yet", opcode & 0xF0);
- break;
- }
-
- // figure out where the previous 2 blocks started
- if (pixelPtr == 0)
- prevBlockPtr1 = (rowPtr - _surface->w * 4) + _surface->w - 4 * 2;
- else if (pixelPtr == 4)
- prevBlockPtr1 = (rowPtr - _surface->w * 4) + rowInc;
- else
- prevBlockPtr1 = rowPtr + pixelPtr - 4 * 2;
-
- if (pixelPtr == 0)
- prevBlockPtr2 = (rowPtr - _surface->w * 4) + rowInc;
- else
- prevBlockPtr2 = rowPtr + pixelPtr - 4;
-
- prevBlockFlag = 0;
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
-
- if (prevBlockFlag)
- prevBlockPtr = prevBlockPtr2;
- else
- prevBlockPtr = prevBlockPtr1;
-
- prevBlockFlag = !prevBlockFlag;
-
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++)
- pixels[blockPtr++] = pixels[prevBlockPtr++];
-
- blockPtr += rowInc;
- prevBlockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 1-color block encoding
- case 0x60:
- case 0x70:
- numBlocks = GET_BLOCK_COUNT();
- pixel = stream->readByte();
-
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++)
- pixels[blockPtr++] = pixel;
-
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 2-color block encoding
- case 0x80:
- case 0x90:
- numBlocks = (opcode & 0x0F) + 1;
-
- // figure out which color pair to use to paint the 2-color block
- if ((opcode & 0xF0) == 0x80) {
- // fetch the next 2 colors from bytestream and store in next
- // available entry in the color pair table
- for (byte i = 0; i < CPAIR; i++) {
- pixel = stream->readByte();
- colorTableIndex = CPAIR * colorPairIndex + i;
- _colorPairs[colorTableIndex] = pixel;
- }
-
- // this is the base index to use for this block
- colorTableIndex = CPAIR * colorPairIndex;
- colorPairIndex++;
-
- // wraparound
- if (colorPairIndex == COLORS_PER_TABLE)
- colorPairIndex = 0;
- } else
- colorTableIndex = CPAIR * stream->readByte();
-
- while (numBlocks--) {
- colorFlags = stream->readUint16BE();
- uint16 flagMask = 0x8000;
- blockPtr = rowPtr + pixelPtr;
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++) {
- if (colorFlags & flagMask)
- pixel = colorTableIndex + 1;
- else
- pixel = colorTableIndex;
-
- flagMask >>= 1;
- pixels[blockPtr++] = _colorPairs[pixel];
- }
-
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 4-color block encoding
- case 0xA0:
- case 0xB0:
- numBlocks = (opcode & 0x0F) + 1;
-
- // figure out which color quad to use to paint the 4-color block
- if ((opcode & 0xF0) == 0xA0) {
- // fetch the next 4 colors from bytestream and store in next
- // available entry in the color quad table
- for (byte i = 0; i < CQUAD; i++) {
- pixel = stream->readByte();
- colorTableIndex = CQUAD * colorQuadIndex + i;
- _colorQuads[colorTableIndex] = pixel;
- }
-
- // this is the base index to use for this block
- colorTableIndex = CQUAD * colorQuadIndex;
- colorQuadIndex++;
-
- // wraparound
- if (colorQuadIndex == COLORS_PER_TABLE)
- colorQuadIndex = 0;
- } else
- colorTableIndex = CQUAD * stream->readByte();
-
- while (numBlocks--) {
- colorFlags = stream->readUint32BE();
-
- // flag mask actually acts as a bit shift count here
- byte flagMask = 30;
- blockPtr = rowPtr + pixelPtr;
-
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++) {
- pixel = colorTableIndex + ((colorFlags >> flagMask) & 0x03);
- flagMask -= 2;
- pixels[blockPtr++] = _colorQuads[pixel];
- }
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 8-color block encoding
- case 0xC0:
- case 0xD0:
- numBlocks = (opcode & 0x0F) + 1;
-
- // figure out which color octet to use to paint the 8-color block
- if ((opcode & 0xF0) == 0xC0) {
- // fetch the next 8 colors from bytestream and store in next
- // available entry in the color octet table
- for (byte i = 0; i < COCTET; i++) {
- pixel = stream->readByte();
- colorTableIndex = COCTET * colorOctetIndex + i;
- _colorOctets[colorTableIndex] = pixel;
- }
-
- // this is the base index to use for this block
- colorTableIndex = COCTET * colorOctetIndex;
- colorOctetIndex++;
-
- // wraparound
- if (colorOctetIndex == COLORS_PER_TABLE)
- colorOctetIndex = 0;
- } else
- colorTableIndex = COCTET * stream->readByte();
-
- while (numBlocks--) {
- /*
- For this input of 6 hex bytes:
- 01 23 45 67 89 AB
- Mangle it to this output:
- flags_a = xx012456, flags_b = xx89A37B
- */
-
- // build the color flags
- byte flagData[6];
- stream->read(flagData, 6);
-
- colorFlagsA = ((READ_BE_UINT16(flagData) & 0xFFF0) << 8) | (READ_BE_UINT16(flagData + 2) >> 4);
- colorFlagsB = ((READ_BE_UINT16(flagData + 4) & 0xFFF0) << 8) | ((flagData[1] & 0xF) << 8) |
- ((flagData[3] & 0xF) << 4) | (flagData[5] & 0xf);
-
- colorFlags = colorFlagsA;
-
- // flag mask actually acts as a bit shift count here
- byte flagMask = 21;
- blockPtr = rowPtr + pixelPtr;
- for (byte y = 0; y < 4; y++) {
- // reload flags at third row (iteration y == 2)
- if (y == 2) {
- colorFlags = colorFlagsB;
- flagMask = 21;
- }
-
- for (byte x = 0; x < 4; x++) {
- pixel = colorTableIndex + ((colorFlags >> flagMask) & 0x07);
- flagMask -= 3;
- pixels[blockPtr++] = _colorOctets[pixel];
- }
-
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- // 16-color block encoding (every pixel is a different color)
- case 0xE0:
- numBlocks = (opcode & 0x0F) + 1;
-
- while (numBlocks--) {
- blockPtr = rowPtr + pixelPtr;
- for (byte y = 0; y < 4; y++) {
- for (byte x = 0; x < 4; x++)
- pixels[blockPtr++] = stream->readByte();
-
- blockPtr += rowInc;
- }
- ADVANCE_BLOCK();
- }
- break;
-
- case 0xF0:
- warning("0xF0 opcode seen in SMC chunk (contact the developers)");
- break;
- }
- }
-
- return _surface;
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/smc.h b/engines/mohawk/video/smc.h
deleted file mode 100644
index c52226100e..0000000000
--- a/engines/mohawk/video/smc.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_VIDEO_SMC_H
-#define MOHAWK_VIDEO_SMC_H
-
-#include "graphics/video/codecs/codec.h"
-
-namespace Mohawk {
-
-enum {
- CPAIR = 2,
- CQUAD = 4,
- COCTET = 8,
- COLORS_PER_TABLE = 256
-};
-
-class SMCDecoder : public Graphics::Codec {
-public:
- SMCDecoder(uint16 width, uint16 height);
- ~SMCDecoder() { delete _surface; }
-
- Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
- Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
-
-private:
- Graphics::Surface *_surface;
-
- // SMC color tables
- byte _colorPairs[COLORS_PER_TABLE * CPAIR];
- byte _colorQuads[COLORS_PER_TABLE * CQUAD];
- byte _colorOctets[COLORS_PER_TABLE * COCTET];
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/mohawk/video/video.cpp b/engines/mohawk/video/video.cpp
deleted file mode 100644
index 86ecd4dedf..0000000000
--- a/engines/mohawk/video/video.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "mohawk/resource.h"
-#include "mohawk/video/video.h"
-#include "mohawk/video/qt_player.h"
-
-#include "common/events.h"
-
-namespace Mohawk {
-
-VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) {
-}
-
-VideoManager::~VideoManager() {
- _mlstRecords.clear();
- stopVideos();
-}
-
-void VideoManager::pauseVideos() {
- for (uint16 i = 0; i < _videoStreams.size(); i++)
- _videoStreams[i]->pauseVideo(true);
-}
-
-void VideoManager::resumeVideos() {
- for (uint16 i = 0; i < _videoStreams.size(); i++)
- _videoStreams[i]->pauseVideo(false);
-}
-
-void VideoManager::stopVideos() {
- for (uint16 i = 0; i < _videoStreams.size(); i++)
- delete _videoStreams[i].video;
- _videoStreams.clear();
-}
-
-void VideoManager::playMovie(Common::String filename, uint16 x, uint16 y, bool clearScreen) {
- VideoHandle videoHandle = createVideoHandle(filename, x, y, false);
- if (videoHandle == NULL_VID_HANDLE)
- return;
-
- // Clear screen if requested
- if (clearScreen) {
- _vm->_system->fillScreen(_vm->_system->getScreenFormat().RGBToColor(0, 0, 0));
- _vm->_system->updateScreen();
- }
-
- waitUntilMovieEnds(videoHandle);
-}
-
-void VideoManager::playMovieCentered(Common::String filename, bool clearScreen) {
- VideoHandle videoHandle = createVideoHandle(filename, 0, 0, false);
- if (videoHandle == NULL_VID_HANDLE)
- return;
-
- // Clear screen if requested
- if (clearScreen) {
- _vm->_system->fillScreen(_vm->_system->getScreenFormat().RGBToColor(0, 0, 0));
- _vm->_system->updateScreen();
- }
-
- _videoStreams[videoHandle].x = (_vm->_system->getWidth() - _videoStreams[videoHandle]->getWidth()) / 2;
- _videoStreams[videoHandle].y = (_vm->_system->getHeight() - _videoStreams[videoHandle]->getHeight()) / 2;
-
- waitUntilMovieEnds(videoHandle);
-}
-
-void VideoManager::waitUntilMovieEnds(VideoHandle videoHandle) {
- bool continuePlaying = true;
-
- while (!_videoStreams[videoHandle]->endOfVideo() && !_vm->shouldQuit() && continuePlaying) {
- if (updateBackgroundMovies())
- _vm->_system->updateScreen();
-
- Common::Event event;
- while (_vm->_system->getEventManager()->pollEvent(event)) {
- switch (event.type) {
- case Common::EVENT_RTL:
- case Common::EVENT_QUIT:
- continuePlaying = false;
- break;
- case Common::EVENT_KEYDOWN:
- switch (event.kbd.keycode) {
- case Common::KEYCODE_SPACE:
- _vm->pauseGame();
- break;
- case Common::KEYCODE_ESCAPE:
- continuePlaying = false;
- break;
- default:
- break;
- }
- default:
- break;
- }
- }
-
- // Cut down on CPU usage
- _vm->_system->delayMillis(10);
- }
-
- _videoStreams[videoHandle]->close();
- _videoStreams.clear();
-}
-
-void VideoManager::playBackgroundMovie(Common::String filename, int16 x, int16 y, bool loop) {
- VideoHandle videoHandle = createVideoHandle(filename, x, y, loop);
- if (videoHandle == NULL_VID_HANDLE)
- return;
-
- // Center x if requested
- if (x < 0)
- _videoStreams[videoHandle].x = (_vm->_system->getWidth() - _videoStreams[videoHandle]->getWidth()) / 2;
-
- // Center y if requested
- if (y < 0)
- _videoStreams[videoHandle].y = (_vm->_system->getHeight() - _videoStreams[videoHandle]->getHeight()) / 2;
-}
-
-bool VideoManager::updateBackgroundMovies() {
- bool updateScreen = false;
-
- for (uint32 i = 0; i < _videoStreams.size() && !_vm->shouldQuit(); i++) {
- // Skip deleted videos
- if (!_videoStreams[i].video)
- continue;
-
- // Remove any videos that are over
- if (_videoStreams[i]->endOfVideo()) {
- if (_videoStreams[i].loop) {
- _videoStreams[i]->rewind();
- } else {
- delete _videoStreams[i].video;
- memset(&_videoStreams[i], 0, sizeof(VideoEntry));
- _videoStreams[i].video = NULL;
- continue;
- }
- }
-
- // Check if we need to draw a frame
- if (_videoStreams[i]->needsUpdate()) {
- Graphics::Surface *frame = _videoStreams[i]->decodeNextFrame();
- bool deleteFrame = false;
-
- if (frame && _videoStreams[i].enabled) {
- // Convert from 8bpp to the current screen format if necessary
- if (frame->bytesPerPixel == 1) {
- Graphics::Surface *newFrame = new Graphics::Surface();
- Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat();
- byte *palette = _videoStreams[i]->getPalette();
- assert(palette);
-
- newFrame->create(frame->w, frame->h, pixelFormat.bytesPerPixel);
-
- for (uint16 j = 0; j < frame->h; j++) {
- for (uint16 k = 0; k < frame->w; k++) {
- byte palIndex = *((byte *)frame->getBasePtr(k, j));
- byte r = palette[palIndex * 3];
- byte g = palette[palIndex * 3 + 1];
- byte b = palette[palIndex * 3 + 2];
- if (pixelFormat.bytesPerPixel == 2)
- *((uint16 *)newFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b);
- else
- *((uint32 *)newFrame->getBasePtr(k, j)) = pixelFormat.RGBToColor(r, g, b);
- }
- }
-
- frame = newFrame;
- deleteFrame = true;
- }
-
- // Clip the width/height to make sure we stay on the screen (Myst does this a few times)
- uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x);
- uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y);
- _vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height);
-
- // We've drawn something to the screen, make sure we update it
- updateScreen = true;
-
- // Delete the frame if we're using the buffer from the 8bpp conversion
- if (deleteFrame) {
- frame->free();
- delete frame;
- }
- }
- }
-
- // Update the audio buffer too
- _videoStreams[i]->updateAudioBuffer();
- }
-
- // Return true if we need to update the screen
- return updateScreen;
-}
-
-void VideoManager::activateMLST(uint16 mlstId, uint16 card) {
- Common::SeekableReadStream *mlstStream = _vm->getRawData(ID_MLST, card);
- uint16 recordCount = mlstStream->readUint16BE();
-
- for (uint16 i = 0; i < recordCount; i++) {
- MLSTRecord mlstRecord;
- mlstRecord.index = mlstStream->readUint16BE();
- mlstRecord.movieID = mlstStream->readUint16BE();
- mlstRecord.code = mlstStream->readUint16BE();
- mlstRecord.left = mlstStream->readUint16BE();
- mlstRecord.top = mlstStream->readUint16BE();
-
- for (byte j = 0; j < 2; j++)
- if (mlstStream->readUint16BE() != 0)
- warning("u0[%d] in MLST non-zero", j);
-
- if (mlstStream->readUint16BE() != 0xFFFF)
- warning("u0[2] in MLST not 0xFFFF");
-
- mlstRecord.loop = mlstStream->readUint16BE();
- mlstRecord.volume = mlstStream->readUint16BE();
- mlstRecord.u1 = mlstStream->readUint16BE();
-
- if (mlstRecord.u1 != 1)
- warning("mlstRecord.u1 not 1");
-
- if (mlstRecord.index == mlstId) {
- _mlstRecords.push_back(mlstRecord);
- break;
- }
- }
-
- delete mlstStream;
-}
-
-void VideoManager::playMovie(uint16 id) {
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
- if (_mlstRecords[i].code == id) {
- debug(1, "Play tMOV %d (non-blocking) at (%d, %d) %s", _mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0 ? "looping" : "non-looping");
- createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, _mlstRecords[i].loop != 0);
- return;
- }
-}
-
-void VideoManager::playMovieBlocking(uint16 id) {
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
- if (_mlstRecords[i].code == id) {
- debug(1, "Play tMOV %d (blocking) at (%d, %d)", _mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top);
- VideoHandle videoHandle = createVideoHandle(_mlstRecords[i].movieID, _mlstRecords[i].left, _mlstRecords[i].top, false);
- waitUntilMovieEnds(videoHandle);
- return;
- }
-}
-
-void VideoManager::stopMovie(uint16 id) {
- debug(2, "Stopping movie %d", id);
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
- if (_mlstRecords[i].code == id)
- for (uint16 j = 0; j < _videoStreams.size(); j++)
- if (_mlstRecords[i].movieID == _videoStreams[j].id) {
- delete _videoStreams[i].video;
- memset(&_videoStreams[i].video, 0, sizeof(VideoEntry));
- return;
- }
-}
-
-void VideoManager::enableMovie(uint16 id) {
- debug(2, "Enabling movie %d", id);
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
- if (_mlstRecords[i].code == id)
- for (uint16 j = 0; j < _videoStreams.size(); j++)
- if (_mlstRecords[i].movieID == _videoStreams[j].id) {
- _videoStreams[j].enabled = true;
- return;
- }
-}
-
-void VideoManager::disableMovie(uint16 id) {
- debug(2, "Disabling movie %d", id);
- for (uint16 i = 0; i < _mlstRecords.size(); i++)
- if (_mlstRecords[i].code == id)
- for (uint16 j = 0; j < _videoStreams.size(); j++)
- if (_mlstRecords[i].movieID == _videoStreams[j].id) {
- _videoStreams[j].enabled = false;
- return;
- }
-}
-
-void VideoManager::disableAllMovies() {
- debug(2, "Disabling all movies");
- for (uint16 i = 0; i < _videoStreams.size(); i++)
- _videoStreams[i].enabled = false;
-}
-
-VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop) {
- // First, check to see if that video is already playing
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].id == id)
- return i;
-
- // Otherwise, create a new entry
- VideoEntry entry;
- entry.video = new QTPlayer();
- entry.x = x;
- entry.y = y;
- entry.filename = "";
- entry.id = id;
- entry.loop = loop;
- entry.enabled = true;
- entry->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id));
- entry->load(*_vm->getRawData(ID_TMOV, id));
-
- // Search for any deleted videos so we can take a formerly used slot
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (!_videoStreams[i].video) {
- _videoStreams[i] = entry;
- return i;
- }
-
- // Otherwise, just add it to the list
- _videoStreams.push_back(entry);
- return _videoStreams.size() - 1;
-}
-
-VideoHandle VideoManager::createVideoHandle(Common::String filename, uint16 x, uint16 y, bool loop) {
- // First, check to see if that video is already playing
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (_videoStreams[i].filename == filename)
- return i;
-
- // Otherwise, create a new entry
- VideoEntry entry;
- entry.video = new QTPlayer();
- entry.x = x;
- entry.y = y;
- entry.filename = filename;
- entry.id = 0;
- entry.loop = loop;
- entry.enabled = true;
-
- Common::File *file = new Common::File();
- if (!file->open(filename)) {
- delete file;
- return NULL_VID_HANDLE;
- }
-
- entry->load(*file);
-
- // Search for any deleted videos so we can take a formerly used slot
- for (uint32 i = 0; i < _videoStreams.size(); i++)
- if (!_videoStreams[i].video) {
- _videoStreams[i] = entry;
- return i;
- }
-
- // Otherwise, just add it to the list
- _videoStreams.push_back(entry);
- return _videoStreams.size() - 1;
-}
-
-} // End of namespace Mohawk
diff --git a/engines/mohawk/video/video.h b/engines/mohawk/video/video.h
deleted file mode 100644
index a5d2bde65d..0000000000
--- a/engines/mohawk/video/video.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef MOHAWK_VIDEO_H
-#define MOHAWK_VIDEO_H
-
-#include "graphics/pixelformat.h"
-
-namespace Mohawk {
-
-class MohawkEngine;
-
-struct MLSTRecord {
- uint16 index;
- uint16 movieID;
- uint16 code;
- uint16 left;
- uint16 top;
- uint16 u0[3];
- uint16 loop;
- uint16 volume;
- uint16 u1;
-};
-
-class QTPlayer;
-
-struct VideoEntry {
- QTPlayer *video;
- uint16 x;
- uint16 y;
- bool loop;
- Common::String filename;
- uint16 id; // Riven only
- bool enabled;
-
- QTPlayer *operator->() const { assert(video); return video; }
-};
-
-typedef int32 VideoHandle;
-
-enum {
- NULL_VID_HANDLE = -1
-};
-
-class VideoManager {
-public:
- VideoManager(MohawkEngine *vm);
- ~VideoManager();
-
- // Generic movie functions
- void playMovie(Common::String filename, uint16 x = 0, uint16 y = 0, bool clearScreen = false);
- void playMovieCentered(Common::String filename, bool clearScreen = true);
- void playBackgroundMovie(Common::String filename, int16 x = -1, int16 y = -1, bool loop = false);
- bool updateBackgroundMovies();
- void pauseVideos();
- void resumeVideos();
- void stopVideos();
-
- // Riven-related functions
- void activateMLST(uint16 mlstId, uint16 card);
- void enableMovie(uint16 id);
- void disableMovie(uint16 id);
- void disableAllMovies();
- void playMovie(uint16 id);
- void stopMovie(uint16 id);
- void playMovieBlocking(uint16 id);
-
- // Riven-related variables
- Common::Array<MLSTRecord> _mlstRecords;
-
-private:
- MohawkEngine *_vm;
-
- void waitUntilMovieEnds(VideoHandle videoHandle);
-
- // Keep tabs on any videos playing
- Common::Array<VideoEntry> _videoStreams;
-
- VideoHandle createVideoHandle(uint16 id, uint16 x, uint16 y, bool loop);
- VideoHandle createVideoHandle(Common::String filename, uint16 x, uint16 y, bool loop);
-};
-
-} // End of namespace Mohawk
-
-#endif
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
index 8864c84e2f..b5eb82b456 100644
--- a/engines/parallaction/debug.cpp
+++ b/engines/parallaction/debug.cpp
@@ -42,6 +42,7 @@ Debugger::Debugger(Parallaction *vm)
DCmd_Register("zones", WRAP_METHOD(Debugger, Cmd_Zones));
DCmd_Register("animations", WRAP_METHOD(Debugger, Cmd_Animations));
DCmd_Register("globalflags",WRAP_METHOD(Debugger, Cmd_GlobalFlags));
+ DCmd_Register("toggleglobalflag",WRAP_METHOD(Debugger, Cmd_ToggleGlobalFlag));
DCmd_Register("localflags", WRAP_METHOD(Debugger, Cmd_LocalFlags));
DCmd_Register("locations", WRAP_METHOD(Debugger, Cmd_Locations));
DCmd_Register("gfxobjects", WRAP_METHOD(Debugger, Cmd_GfxObjects));
@@ -117,6 +118,32 @@ bool Debugger::Cmd_GlobalFlags(int argc, const char **argv) {
return true;
}
+bool Debugger::Cmd_ToggleGlobalFlag(int argc, const char **argv) {
+
+ int i;
+
+ switch (argc) {
+ case 2:
+ i = _vm->_globalFlagsNames->lookup(argv[1]);
+ if (i == Table::notFound) {
+ DebugPrintf("invalid flag '%s'\n", argv[1]);
+ } else {
+ i--;
+ if ((_globalFlags & (1 << i)) == 0)
+ _globalFlags |= (1 << i);
+ else
+ _globalFlags &= ~(1 << i);
+ }
+ break;
+
+ default:
+ DebugPrintf("toggleglobalflag <flag name>\n");
+
+ }
+
+ return true;
+}
+
bool Debugger::Cmd_LocalFlags(int argc, const char **argv) {
uint32 flags = _vm->getLocationFlags();
diff --git a/engines/parallaction/debug.h b/engines/parallaction/debug.h
index 54b578e95f..5267206d04 100644
--- a/engines/parallaction/debug.h
+++ b/engines/parallaction/debug.h
@@ -28,6 +28,7 @@ protected:
bool Cmd_Animations(int argc, const char **argv);
bool Cmd_LocalFlags(int argc, const char **argv);
bool Cmd_GlobalFlags(int argc, const char **argv);
+ bool Cmd_ToggleGlobalFlag(int argc, const char **argv);
bool Cmd_Locations(int argc, const char **argv);
bool Cmd_GfxObjects(int argc, const char **argv);
bool Cmd_Programs(int argc, const char** argv);
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
index 6332600226..7a28d18f17 100644
--- a/engines/parallaction/dialogue.cpp
+++ b/engines/parallaction/dialogue.cpp
@@ -461,6 +461,10 @@ public:
void Parallaction::enterDialogueMode(ZonePtr z) {
+ if (!z->u._speakDialogue) {
+ return;
+ }
+
debugC(1, kDebugDialogue, "Parallaction::enterDialogueMode(%s)", z->u._filename.c_str());
_dialogueMan = createDialogueManager(z);
assert(_dialogueMan);
diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp
index 13c1318123..1d8724e2d8 100644
--- a/engines/parallaction/exec_br.cpp
+++ b/engines/parallaction/exec_br.cpp
@@ -337,7 +337,7 @@ DECLARE_COMMAND_OPCODE(speak) {
return;
}
- if (ACTIONTYPE(ctxt._cmd->_zone) == kZoneSpeak) {
+ if (ACTIONTYPE(ctxt._cmd->_zone) == kZoneSpeak && ctxt._cmd->_zone->u._speakDialogue) {
_vm->enterDialogueMode(ctxt._cmd->_zone);
} else {
_vm->_activeZone = ctxt._cmd->_zone;
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 326ae2c519..2990d024d2 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -538,12 +538,12 @@ GfxObj *Gfx::renderFloatingLabel(Font *font, char *text) {
setupLabelSurface(*cnv, w, h);
- font->setColor((_vm->getGameType() == GType_BRA) ? 0 : 7);
+ font->setColor((_gameType == GType_BRA) ? 0 : 7);
font->drawString((byte*)cnv->pixels + 1, cnv->w, text);
font->drawString((byte*)cnv->pixels + 1 + cnv->w * 2, cnv->w, text);
font->drawString((byte*)cnv->pixels + cnv->w, cnv->w, text);
font->drawString((byte*)cnv->pixels + 2 + cnv->w, cnv->w, text);
- font->setColor((_vm->getGameType() == GType_BRA) ? 11 : 1);
+ font->setColor((_gameType == GType_BRA) ? 11 : 1);
font->drawString((byte*)cnv->pixels + 1 + cnv->w, cnv->w, text);
} else {
w = font->getStringWidth(text);
@@ -835,7 +835,7 @@ void Gfx::setBackground(uint type, BackgroundInfo *info) {
// The PC version of BRA needs the entries 20-31 of the palette to be constant, but
// the background resource files are screwed up. The right colors come from an unused
// bitmap (pointer.bmp). Nothing is known about the Amiga version so far.
- if ((_vm->getGameType() == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) {
+ if ((_gameType == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) {
int r, g, b;
for (uint i = 16; i < 32; i++) {
_backupPal.getEntry(i, r, g, b);
diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp
index 7ad1be8681..ca8f358158 100644
--- a/engines/parallaction/input.cpp
+++ b/engines/parallaction/input.cpp
@@ -203,13 +203,13 @@ int Input::updateGameInput() {
return event;
}
- if (_vm->getGameType() == GType_Nippon) {
+ if (_gameType == GType_Nippon) {
if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) {
if (_keyPressed.keycode == Common::KEYCODE_l) event = kEvLoadGame;
if (_keyPressed.keycode == Common::KEYCODE_s) event = kEvSaveGame;
}
} else
- if (_vm->getGameType() == GType_BRA) {
+ if (_gameType == GType_BRA) {
if (_hasKeyPressEvent && (_vm->getFeatures() & GF_DEMO) == 0) {
if (_keyPressed.keycode == Common::KEYCODE_F5) event = kEvIngameMenu;
}
@@ -325,8 +325,13 @@ bool Input::translateGameInput() {
if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || (ACTIONTYPE(z) == kZoneCommand))) {
- if (z->_flags & kFlagsNoWalk) {
- // character doesn't need to walk to take specified action
+ bool noWalk = z->_flags & kFlagsNoWalk; // check the explicit no-walk flag
+ if (_gameType == GType_BRA) {
+ // action performed on object marked for self-use do not need walk in BRA
+ noWalk |= ((z->_flags & kFlagsYourself) != 0);
+ }
+
+ if (noWalk) {
takeAction(z);
} else {
// action delayed: if Zone defined a moveto position the character is programmed to move there,
@@ -351,7 +356,7 @@ bool Input::translateGameInput() {
void Input::enterInventoryMode() {
Common::Point mousePos;
- getCursorPos(mousePos);
+ getAbsoluteCursorPos(mousePos);
bool hitCharacter = _vm->hitZone(kZoneYou, mousePos.x, mousePos.y);
if (hitCharacter) {
diff --git a/engines/parallaction/objects.h b/engines/parallaction/objects.h
index 50a789247f..36231cfcc5 100644
--- a/engines/parallaction/objects.h
+++ b/engines/parallaction/objects.h
@@ -88,9 +88,9 @@ enum ZoneFlags {
kFlagsNoWalk = 0x800, // Zone: character doesn't need to walk towards object to interact
// BRA specific
- kFlagsYourself = 0x1000,
+ kFlagsYourself = 0x1000, // BRA: marks zones used by the character on him/herself
kFlagsScaled = 0x2000,
- kFlagsSelfuse = 0x4000,
+ kFlagsSelfuse = 0x4000, // BRA: marks zones to be preserved across location changes (see Parallaction::freeZones)
kFlagsIsAnimation = 0x1000000, // BRA: used in walk code (trap check), to tell is a Zone is an Animation
kFlagsAnimLinked = 0x2000000
};
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
index cb208a17ff..ce7525345a 100644
--- a/engines/parallaction/parallaction.cpp
+++ b/engines/parallaction/parallaction.cpp
@@ -102,7 +102,8 @@ Parallaction::~Parallaction() {
Common::Error Parallaction::init() {
-
+
+ _gameType = getGameType();
_engineFlags = 0;
_objectsNames = NULL;
_globalFlagsNames = NULL;
@@ -408,7 +409,7 @@ void Parallaction::drawAnimation(AnimationPtr anim) {
uint16 layer = LAYER_FOREGROUND;
uint16 scale = 100;
- switch (getGameType()) {
+ switch (_gameType) {
case GType_Nippon:
if ((anim->_flags & kFlagsNoMasked) == 0) {
// Layer in NS depends on where the animation is on the screen, for each animation.
@@ -523,7 +524,7 @@ void Parallaction::enterCommentMode(ZonePtr z) {
}
// TODO: move this balloons stuff into DialogueManager and BalloonManager
- if (getGameType() == GType_Nippon) {
+ if (_gameType == GType_Nippon) {
if (!data->_filename.empty()) {
if (data->_gfxobj == 0) {
data->_gfxobj = _disk->loadStatic(data->_filename.c_str());
@@ -540,7 +541,7 @@ void Parallaction::enterCommentMode(ZonePtr z) {
_gfx->setItem(_char._talk, 190, 80);
}
} else
- if (getGameType() == GType_BRA) {
+ if (_gameType == GType_BRA) {
_balloonMan->setSingleBalloon(data->_examineText.c_str(), 0, 0, 1, BalloonManager::kNormalColor);
_gfx->setItem(_char._talk, 10, 80);
}
@@ -651,13 +652,21 @@ bool Parallaction::pickupItem(ZonePtr z) {
return (slot != -1);
}
-// FIXME: input coordinates must be offseted to handle scrolling!
bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
- // not a special zone
- if ((z->getX() != -2) && (z->getX() != -3)) {
- return false;
+ // check if really a special zone
+ if (_gameType == GType_Nippon) {
+ // so-called special zones in NS have special x coordinates
+ if ((z->getX() != -2) && (z->getX() != -3)) {
+ return false;
+ }
}
-
+ if (_gameType == GType_BRA) {
+ // so far, special zones in BRA are only merge zones
+ if (ACTIONTYPE(z) != kZoneMerge) {
+ return false;
+ }
+ }
+
// WORKAROUND: this huge condition is needed because we made TypeData a collection of structs
// instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine,
// but we need to check it separately here. The same workaround is applied in freeZones.
@@ -681,7 +690,33 @@ bool Parallaction::checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
return false;
}
-// FIXME: input coordinates must be offseted to handle scrolling!
+bool Parallaction::checkZoneType(ZonePtr z, uint32 type) {
+ if (_gameType == GType_Nippon) {
+ if ((type == 0) && (ITEMTYPE(z) == 0))
+ return true;
+ }
+
+ if (_gameType == GType_BRA) {
+ if (type == 0) {
+ if (ITEMTYPE(z) == 0) {
+ if (ACTIONTYPE(z) != kZonePath) {
+ return true;
+ }
+ }
+ if (ACTIONTYPE(z) == kZoneDoor) {
+ return true;
+ }
+ }
+ }
+
+ if (z->_type == type)
+ return true;
+ if (ITEMTYPE(z) == type)
+ return true;
+
+ return false;
+}
+
bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
if (z->_flags & kFlagsRemove)
return false;
@@ -689,29 +724,30 @@ bool Parallaction::checkZoneBox(ZonePtr z, uint32 type, uint x, uint y) {
debugC(5, kDebugExec, "checkZoneBox for %s (type = %x, x = %i, y = %i)", z->_name, type, x, y);
if (!z->hitRect(x, y)) {
-
// check for special zones (items defined in common.loc)
if (checkSpecialZoneBox(z, type, x, y))
return true;
- if (z->getX() != -1)
- return false;
- if (!_char._ani->hitFrameRect(x, y))
+ // check if self-use zone (nothing to do with kFlagsSelfuse)
+ if (_gameType == GType_Nippon) {
+ if (z->getX() != -1) { // no explicit self-use flag in NS
+ return false;
+ }
+ }
+ if (_gameType == GType_BRA) {
+ if (!(z->_flags & kFlagsYourself)) {
+ return false;
+ }
+ }
+ if (!_char._ani->hitFrameRect(x, y)) {
return false;
+ }
+ // we get here only if (x,y) hits the character and the zone is marked as self-use
}
- // normal Zone
- if ((type == 0) && (ITEMTYPE(z) == 0))
- return true;
- if (z->_type == type)
- return true;
- if (ITEMTYPE(z) == type)
- return true;
-
- return false;
+ return checkZoneType(z, type);
}
-// FIXME: input coordinates must be offseted to handle scrolling!
bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) {
if (z->_flags & kFlagsRemove)
return false;
@@ -727,18 +763,14 @@ bool Parallaction::checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y) {
return false;
}
- // NOTE: the implementation of the following lines is a different in the
- // original... it is working so far, though
- if ((type == 0) && (ITEMTYPE(z) == 0))
- return true;
- if (z->_type == type)
- return true;
- if (ITEMTYPE(z) == type)
- return true;
-
- return false;
+ return checkZoneType(z, type);
}
+/* NOTE: hitZone needs to be passed absolute game coordinates to work.
+
+ When type is kZoneMerge, then x and y are the identifiers of the objects to merge,
+ and the above requirement does not apply.
+*/
ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
uint16 _di = y;
uint16 _si = x;
@@ -752,14 +784,20 @@ ZonePtr Parallaction::hitZone(uint32 type, uint16 x, uint16 y) {
}
}
-
int16 _a, _b, _c, _d;
bool _ef;
for (AnimationList::iterator ait = _location._animations.begin(); ait != _location._animations.end(); ++ait) {
AnimationPtr a = *ait;
- _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation
+ _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation
+
+ if (!_a) {
+ if (_gameType == GType_BRA && ACTIONTYPE(a) != kZoneTrap) {
+ continue;
+ }
+ }
+
_ef = a->hitFrameRect(_si, _di);
_b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character)
@@ -951,7 +989,7 @@ bool CharacterName::dummy() const {
}
void Parallaction::beep() {
- if (getGameType() == GType_Nippon) {
+ if (_gameType == GType_Nippon) {
_soundMan->execute(SC_SETSFXCHANNEL, 3);
_soundMan->execute(SC_SETSFXVOLUME, 127);
_soundMan->execute(SC_SETSFXLOOPING, (int32)0);
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index 3a84aa215e..7bbdf79f1c 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -280,6 +280,7 @@ public:
int32 _screenWidth;
int32 _screenHeight;
int32 _screenSize;
+ int _gameType;
// subsystems
Gfx *_gfx;
@@ -360,6 +361,7 @@ public:
uint32 getLocationFlags();
bool checkSpecialZoneBox(ZonePtr z, uint32 type, uint x, uint y);
bool checkZoneBox(ZonePtr z, uint32 type, uint x, uint y);
+ bool checkZoneType(ZonePtr z, uint32 type);
bool checkLinkedAnimBox(ZonePtr z, uint32 type, uint x, uint y);
ZonePtr hitZone(uint32 type, uint16 x, uint16 y);
void runZone(ZonePtr z);
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index ee718189b5..470c698a21 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -196,7 +196,7 @@ void Parallaction_br::runPendingZones() {
if (_activeZone) {
z = _activeZone; // speak Zone or sound
_activeZone.reset();
- if (ACTIONTYPE(z) == kZoneSpeak) {
+ if (ACTIONTYPE(z) == kZoneSpeak && z->u._speakDialogue) {
enterDialogueMode(z);
} else {
runZone(z); // FIXME: BRA doesn't handle sound yet
@@ -206,7 +206,7 @@ void Parallaction_br::runPendingZones() {
if (_activeZone2) {
z = _activeZone2; // speak Zone or sound
_activeZone2.reset();
- if (ACTIONTYPE(z) == kZoneSpeak) {
+ if (ACTIONTYPE(z) == kZoneSpeak && z->u._speakDialogue) {
enterDialogueMode(z);
} else {
runZone(z); // FIXME: BRA doesn't handle sound yet
diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp
index 928f3f5b74..df1e91e8b4 100644
--- a/engines/parallaction/parser.cpp
+++ b/engines/parallaction/parser.cpp
@@ -44,8 +44,10 @@ Script::~Script() {
/*
* readLineIntern read a text line and prepares it for
* parsing, by stripping the leading whitespace and
- * changing tabs to spaces. It will stop on a CR or LF,
- * and return an empty string (length = 0) when a line
+ * changing tabs to spaces. It will stop on a CR, LF, or
+ * SUB (0x1A), which may all occur at the end of a script
+ * line.
+ * Returns an empty string (length = 0) when a line
* has no printable text in it.
*/
char *Script::readLineIntern(char *buf, size_t bufSize) {
@@ -54,7 +56,8 @@ char *Script::readLineIntern(char *buf, size_t bufSize) {
char c = _input->readSByte();
if (_input->eos())
break;
- if (c == '\n' || c == '\r')
+ // break if EOL
+ if (c == '\n' || c == '\r' || c == (char)0x1A)
break;
if (c == '\t')
c = ' ';
diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp
index be72cf73a1..ff24a06ceb 100644
--- a/engines/parallaction/parser_ns.cpp
+++ b/engines/parallaction/parser_ns.cpp
@@ -286,6 +286,7 @@ void LocationParser_ns::parseAnimation(AnimationList &list, char *name) {
debugC(5, kDebugParser, "parseAnimation(name: %s)", name);
if (_vm->_location.findAnimation(name)) {
+ _zoneProg++;
_script->skip("endanimation");
return;
}
@@ -1305,6 +1306,7 @@ void LocationParser_ns::parseZone(ZoneList &list, char *name) {
debugC(5, kDebugParser, "parseZone(name: %s)", name);
if (_vm->_location.findZone(name)) {
+ _zoneProg++;
_script->skip("endzone");
return;
}
diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp
index 1c724ddc1c..407dd86ec3 100644
--- a/engines/parallaction/sound_br.cpp
+++ b/engines/parallaction/sound_br.cpp
@@ -172,11 +172,11 @@ bool MidiParser_MSC::loadMusic(byte *data, uint32 size) {
byte *pos = data;
- uint32 signature = read4high(pos);
- if (memcmp("tCSM", &signature, 4)) {
+ if (memcmp("MSCt", pos, 4)) {
warning("Expected header not found in music file.");
return false;
}
+ pos += 4;
_beats = read1(pos);
_ppqn = read2low(pos);
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index 025462c558..1b7fa97f8d 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -316,20 +316,6 @@ Common::Error SagaEngine::run() {
syncSoundSettings();
-
-#if 0
- // FIXME: Disabled this code for now. We want to get rid of OSystem::kFeatureAutoComputeDirtyRects
- // and this is the last place to make use of it. We need to find out whether doing
- // so causes any regressions. If it does, we can reenable it, if not, we can remove
- // this code in 0.13.0.
-
- // FIXME: This is the ugly way of reducing redraw overhead. It works
- // well for 320x200 but it's unclear how well it will work for
- // 640x480.
- if (getGameId() == GID_ITE)
- _system->setFeatureState(OSystem::kFeatureAutoComputeDirtyRects, true);
-#endif
-
int msec = 0;
_previousTicks = _system->getMillis();
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 3ba550adf9..4c940804b8 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -332,6 +332,8 @@ uint16 Script::validateExportFunc(int pubfunct) {
if (offset == 0) {
// Check if the game has a second export table (e.g. script 912 in Camelot)
// Fixes bug #3039785
+ if (g_sci->getGameId() == GID_ECOQUEST) // cheap fix in here for eco quest 1, [md5] plz look into this TODO FIXME
+ return offset;
const uint16 *secondExportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS, 0);
if (secondExportTable) {
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index e5fcbf72c2..5fc93421cd 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -51,8 +51,72 @@ struct SciScriptSignature {
// - if not EOS, an adjust offset and the actual bytes
// - rinse and repeat
+// stayAndHelp::changeState (0) is called when ego swims to the left or right
+// boundaries of room 660. Normally a textbox is supposed to get on screen
+// but the call is wrong, so not only do we get an error message the script
+// is also hanging because the cue won't get sent out
+// This also happens in sierra sci - ffs. bug #3038387
+const byte ecoquest1SignatureStayAndHelp[] = {
+ 40,
+ 0x3f, 0x01, // link 01
+ 0x87, 0x01, // lap param[1]
+ 0x65, 0x14, // aTop state
+ 0x36, // push
+ 0x3c, // dup
+ 0x35, 0x00, // ldi 00
+ 0x1a, // eq?
+ 0x31, 0x1c, // bnt [next state]
+ 0x76, // push0
+ 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off)
+ 0x38, 0x22, 0x01, // pushi 0122
+ 0x78, // push1
+ 0x76, // push0
+ 0x81, 0x00, // lag global[0]
+ 0x4a, 0x06, // send 06 - ego::setMotion(0)
+ 0x39, 0x6e, // pushi 6e (selector init)
+ 0x39, 0x04, // pushi 04
+ 0x76, // push0
+ 0x76, // push0
+ 0x39, 0x17, // pushi 17
+ 0x7c, // pushSelf
+ 0x51, 0x82, // class EcoNarrator
+ 0x4a, 0x0c, // send 0c - EcoNarrator::init(0, 0, 23, self) (BADLY BROKEN!)
+ 0x33, // jmp [end]
+ 0
+};
-// daySixBeignet::changeState is called when the cop goes out and sets cycles to 220.
+const uint16 ecoquest1PatchStayAndHelp[] = {
+ 0x87, 0x01, // lap param[1]
+ 0x65, 0x14, // aTop state
+ 0x36, // push
+ 0x2f, 0x22, // bt [next state] (this optimization saves 6 bytes)
+ 0x39, 0x00, // pushi 0 (wasting 1 byte here)
+ 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off)
+ 0x38, 0x22, 0x01, // pushi 0122
+ 0x78, // push1
+ 0x76, // push0
+ 0x81, 0x00, // lag global[0]
+ 0x4a, 0x06, // send 06 - ego::setMotion(0)
+ 0x39, 0x6e, // pushi 6e (selector init)
+ 0x39, 0x06, // pushi 06
+ 0x39, 0x02, // pushi 02 (additional 2 bytes)
+ 0x76, // push0
+ 0x76, // push0
+ 0x39, 0x17, // pushi 17
+ 0x7c, // pushSelf
+ 0x38, 0x80, 0x02, // pushi 280 (additional 3 bytes)
+ 0x51, 0x82, // class EcoNarrator
+ 0x4a, 0x10, // send 10 - EcoNarrator::init(2, 0, 0, 23, self, 640)
+ PATCH_END
+};
+
+// script, description, magic DWORD, adjust
+const SciScriptSignature ecoquest1Signatures[] = {
+ { 660, "CD: bad messagebox and freeze", PATCH_MAGICDWORD(0x38, 0x22, 0x01, 0x78), -17, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp },
+ { 0, NULL, 0, 0, NULL, NULL }
+};
+
+// daySixBeignet::changeState (4) is called when the cop goes out and sets cycles to 220.
// this is not enough time to get to the door, so we patch that to 23 seconds
const byte gk1SignatureDay6PoliceBeignet[] = {
4,
@@ -78,12 +142,14 @@ const uint16 gk1PatchDay6PoliceBeignet[] = {
PATCH_END
};
+// sargSleeping::changeState (8) is called when the cop falls asleep and sets cycles to 220.
+// this is not enough time to get to the door, so we patch it to 42 seconds
const byte gk1SignatureDay6PoliceSleep[] = {
4,
0x35, 0x08, // ldi 08
0x1a, // eq?
0x31, // bnt [next state check]
- +1, 5, // [skip 1 byte, offset of bnt]
+ +1, 6, // [skip 1 byte, offset of bnt]
0x34, 0xdc, 0x00, // ldi 220
0x65, 0x1a, // aTop cycles
0x32, // jmp [end]
@@ -97,8 +163,27 @@ const uint16 gk1PatchDay6PoliceSleep[] = {
PATCH_END
};
+// startOfDay5::changeState (20h) - when gabriel goes to the phone the script will hang
+const byte gk1SignatureDay5PhoneFreeze[] = {
+ 5,
+ 0x35, 0x03, // ldi 03
+ 0x65, 0x1a, // aTop cycles
+ 0x32, // jmp [end]
+ +2, 3, // [skip 2 bytes, offset of jmp]
+ 0x3c, // dup
+ 0x35, 0x21, // ldi 21
+ 0
+};
+
+const uint16 gk1PatchDay5PhoneFreeze[] = {
+ 0x35, 0x06, // ldi 06
+ 0x65, 0x20, // aTop ticks
+ PATCH_END
+};
+
// script, description, magic DWORD, adjust
const SciScriptSignature gk1Signatures[] = {
+ { 212, "day 5 phone freeze", PATCH_MAGICDWORD(0x35, 0x03, 0x65, 0x1a), 0, gk1SignatureDay5PhoneFreeze, gk1PatchDay5PhoneFreeze },
{ 230, "day 6 police beignet timer issue", PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -16, gk1SignatureDay6PoliceBeignet, gk1PatchDay6PoliceBeignet },
{ 230, "day 6 police sleep timer issue", PATCH_MAGICDWORD(0x34, 0xdc, 0x00, 0x65), -5, gk1SignatureDay6PoliceSleep, gk1PatchDay6PoliceSleep },
{ 0, NULL, 0, 0, NULL, NULL }
@@ -325,6 +410,8 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr
void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
const SciScriptSignature *signatureTable = NULL;
+ if (g_sci->getGameId() == GID_ECOQUEST)
+ signatureTable = ecoquest1Signatures;
if (g_sci->getGameId() == GID_GK1)
signatureTable = gk1Signatures;
// hoyle4 now works due workaround inside GfxPorts
@@ -341,7 +428,7 @@ void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uin
int32 foundOffset = findSignature(signatureTable, scriptData, scriptSize);
if (foundOffset != -1) {
// found, so apply the patch
- warning("matched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset);
+ warning("matched and patched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset);
applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset);
}
}
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 4dc4ae93d8..013858dbcc 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -114,6 +114,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_JONES, 764, 255, 0, "", "export 0", -1, 14, { WORKAROUND_FAKE, 0 } }, // jones/ega&vga only - called when the game starts
{ GID_KQ5, -1, 0, 0, "", "export 29", -1, 3, { WORKAROUND_FAKE, 0 } }, // called when playing harp for the harpies or when aborting dialog in toy shop, is used for kDoAudio - bug #3034700
{ GID_KQ5, 25, 25, 0, "rm025", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // inside witch forest, when going to the room where the walking rock is
+ { GID_KQ5, 55, 55, 0, "helpScript", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // when giving the tambourine to the monster in the labyrinth (only happens at one of the locations) - bug #3041262
{ GID_KQ6, -1, 30, 0, "rats", "changeState", -1, -1, { WORKAROUND_FAKE, 0 } }, // rats in the catacombs (temps 1 - 5) - bugs #3034597, #3035495, #3035824
{ GID_KQ6, 210, 210, 0, "rm210", "scriptCheck", -1, 0, { WORKAROUND_FAKE, 1 } }, // using inventory in that room - bug #3034565
{ GID_KQ6, 500, 500, 0, "rm500", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // going to island of the beast
@@ -124,8 +125,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_LAURABOW, -1, 967, 0, "myIcon", "cycle", -1, 1, { WORKAROUND_FAKE, 0 } }, // having any portrait conversation coming up (initial bug #3034985)
{ GID_LAURABOW2, -1, 24, 0, "gcWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu
{ GID_LAURABOW2, -1, 21, 0, "dropCluesCode", "doit", -1, 1, { WORKAROUND_FAKE, 0x7fff } }, // when asking some questions (e.g. the reporter about the burglary, or the policeman about Ziggy). Must be big, as the game scripts perform lt on it and start deleting journal entries - bugs #3035068, #3036274
- { GID_LAURABOW2, -1, 90, 0, "aTut", "init", -1, 6, { WORKAROUND_FAKE, 0 } }, // Random actors in museum (bug #3041257)
- { GID_LAURABOW2, -1, 90, 0, "aZiggy", "init", -1, 6, { WORKAROUND_FAKE, 0 } }, // Random actors in museum (bug #3041257)
+ { GID_LAURABOW2, -1, 90, 1, "MuseumActor", "init", -1, 6, { WORKAROUND_FAKE, 0 } }, // Random actors in museum (bug #3041257)
{ GID_LAURABOW2, 240, 240, 0, "sSteveAnimates", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // Steve Dorian's idle animation at the docks - bug #3036291
{ GID_LONGBOW, -1, 213, 0, "clear", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // When giving an answer using the druid hand sign code in any room
{ GID_LONGBOW, -1, 213, 0, "letter", "handleEvent", 0xa8, 1, { WORKAROUND_FAKE, 0 } }, // When using the druid hand sign code in any room - bug #3036601
@@ -155,6 +155,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_QFG3, 330, 330, -1, "Teller", "doChild", -1, -1, { WORKAROUND_FAKE, 0 } }, // when talking to King Rajah about "Rajah" (bug #3036390, temp 1) or "Tarna" (temp 0), or when clicking on yourself and saying "Greet" (bug #3039774, temp 1)
{ GID_QFG3, 700, 700, -1, "monsterIsDead", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // in the jungle, after winning any fight, bug #3040624
{ GID_QFG3, 470, 470, -1, "rm470", "notify", -1, 0, { WORKAROUND_FAKE, 0 } }, // closing the character screen in the Simbani village in the room with the bridge, bug #3040565
+ { GID_QFG3, 490, 490, -1, "computersMove", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // when finishing awari game, bug #3040579
{ GID_QFG4, -1, 15, -1, "charInitScreen", "dispatchEvent", -1, 5, { WORKAROUND_FAKE, 0 } }, // floppy version, when viewing the character screen
{ GID_QFG4, -1, 64917, -1, "controlPlane", "setBitmap", -1, 3, { WORKAROUND_FAKE, 0 } }, // floppy version, when entering the game menu
{ GID_QFG4, -1, 64917, -1, "Plane", "setBitmap", -1, 3, { WORKAROUND_FAKE, 0 } }, // floppy version, happen sometimes in fights
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index ab4362cda9..913b369790 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -243,6 +243,8 @@ void GfxAnimate::fill(byte &old_picNotValid) {
}
}
+ //warning("%s", _s->_segMan->getObjectName(curObject));
+
if (!view->isScaleable()) {
// Laura Bow 2 (especially floppy) depends on this, some views are not supposed to be scaleable
// this "feature" was removed in later versions of SCI1.1
@@ -516,6 +518,19 @@ void GfxAnimate::reAnimate(Common::Rect rect) {
}
}
+void GfxAnimate::preprocessAddToPicList() {
+ AnimateList::iterator it;
+ const AnimateList::iterator end = _list.end();
+
+ for (it = _list.begin(); it != end; ++it) {
+ if (it->priority == -1)
+ it->priority = _ports->kernelCoordinateToPriority(it->y);
+
+ // Do not allow priority to get changed by fill()
+ it->signal |= kSignalFixedPriority;
+ }
+}
+
void GfxAnimate::addToPicDrawCels() {
reg_t curObject;
GfxView *view = NULL;
@@ -525,17 +540,11 @@ void GfxAnimate::addToPicDrawCels() {
for (it = _list.begin(); it != end; ++it) {
curObject = it->object;
- if (it->priority == -1)
- it->priority = _ports->kernelCoordinateToPriority(it->y);
-
// Get the corresponding view
view = _cache->getView(it->viewId);
- // Create rect according to coordinates and given cel
- view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
-
// draw corresponding cel
- _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo);
+ _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
if ((it->signal & kSignalIgnoreActor) == 0) {
it->celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, it->celRect.top, it->celRect.bottom - 1);
_paint16->fillRect(it->celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
@@ -679,6 +688,7 @@ void GfxAnimate::addToPicSetPicNotValid() {
void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv) {
List *list;
+ byte tempPicNotValid = 0;
_ports->setPort((Port *)_ports->_picWind);
@@ -687,6 +697,8 @@ void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv)
error("kAddToPic called with non-list as parameter");
makeSortedList(list);
+ preprocessAddToPicList();
+ fill(tempPicNotValid);
addToPicDrawCels();
addToPicSetPicNotValid();
diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h
index 7e82187eed..c2101e5384 100644
--- a/engines/sci/graphics/animate.h
+++ b/engines/sci/graphics/animate.h
@@ -100,6 +100,7 @@ public:
void updateScreen(byte oldPicNotValid);
void restoreAndDelete(int argc, reg_t *argv);
void reAnimate(Common::Rect rect);
+ void preprocessAddToPicList();
void addToPicDrawCels();
void addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control);
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 1c865f6bcf..5f48574dcb 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -256,6 +256,8 @@ void GfxView::initData(GuiResourceId resourceId) {
cel->scriptHeight = cel->height = READ_SCI11ENDIAN_UINT16(celData + 2);
cel->displaceX = READ_SCI11ENDIAN_UINT16(celData + 4);
cel->displaceY = READ_SCI11ENDIAN_UINT16(celData + 6);
+ if (cel->displaceY < 0)
+ cel->displaceY += 255; // sierra did this adjust in their sci1.1 getCelRect() - not sure about sci32
assert(cel->width && cel->height);
diff --git a/engines/sci/sound/iterator/core.cpp b/engines/sci/sound/iterator/core.cpp
deleted file mode 100644
index 7cd730b3e2..0000000000
--- a/engines/sci/sound/iterator/core.cpp
+++ /dev/null
@@ -1,1013 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/* Sound subsystem core: Event handler, sound player dispatching */
-
-#include "sci/sci.h"
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-
-#include "sci/sound/iterator/core.h"
-#include "sci/sound/iterator/iterator.h"
-#include "sci/sound/drivers/mididriver.h"
-
-#include "common/system.h"
-#include "common/timer.h"
-
-#include "sound/mixer.h"
-
-namespace Sci {
-
-/* Plays a song iterator that found a PCM through a PCM device, if possible
-** Parameters: (SongIterator *) it: The iterator to play
-** (SongHandle) handle: Debug handle
-** Returns : (int) 0 if the effect will not be played, nonzero if it will
-** This assumes that the last call to 'it->next()' returned SI_PCM.
-*/
-static int sfx_play_iterator_pcm(SongIterator *it, SongHandle handle);
-
-
-#pragma mark -
-
-
-class SfxPlayer {
-public:
- /** Number of voices that can play simultaneously */
- int _polyphony;
-
-protected:
- SciVersion _soundVersion;
- MidiPlayer *_mididrv;
-
- SongIterator *_iterator;
- Audio::Timestamp _wakeupTime;
- Audio::Timestamp _currentTime;
- uint32 _pauseTimeDiff;
-
- bool _paused;
- bool _iteratorIsDone;
- uint32 _tempo;
-
- Common::Mutex _mutex;
- int _volume;
-
- void play_song(SongIterator *it);
- static void player_timer_callback(void *refCon);
-
-public:
- SfxPlayer(SciVersion soundVersion);
- ~SfxPlayer();
-
- /**
- * Initializes the player.
- * @param resMan a resource manager for driver initialization
- * @param expected_latency expected delay in between calls to 'maintenance' (in microseconds)
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error init(ResourceManager *resMan, int expected_latency);
-
- /**
- * Adds an iterator to the song player
- * @param it The iterator to play
- * @param start_time The time to assume as the time the first MIDI command executes at
- * @return Common::kNoError on success, Common::kUnknownError on failure
- *
- * The iterator should not be cloned (to avoid memory leaks) and
- * may be modified according to the needs of the player.
- * Implementors may use the 'sfx_iterator_combine()' function
- * to add iterators onto their already existing iterators.
- */
- Common::Error add_iterator(SongIterator *it, uint32 start_time);
-
- /**
- * Stops the currently playing song and deletes the associated iterator.
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error stop();
-
- /**
- * Transmits a song iterator message to the active song.
- * @param msg the message to transmit
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error iterator_message(const SongIterator::Message &msg);
-
- /**
- * Pauses song playing.
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error pause();
-
- /**
- * Resumes song playing after a pause.
- * @return Common::kNoError on success, Common::kUnknownError on failure
- */
- Common::Error resume();
-
- /**
- * Pass a raw MIDI event to the synth.
- * @param argc length of buffer holding the midi event
- * @param argv the buffer itself
- */
- void tell_synth(int buf_nr, byte *buf);
-
- void setVolume(int vol);
-
- int getVolume();
-};
-
-SfxPlayer::SfxPlayer(SciVersion soundVersion)
- : _soundVersion(soundVersion), _wakeupTime(0, SFX_TICKS_PER_SEC), _currentTime(0, 1) {
- _polyphony = 0;
-
- _mididrv = 0;
-
- _iterator = NULL;
- _pauseTimeDiff = 0;
-
- _paused = false;
- _iteratorIsDone = false;
- _tempo = 0;
-
- _volume = 15;
-}
-
-SfxPlayer::~SfxPlayer() {
- if (_mididrv) {
- _mididrv->close();
- delete _mididrv;
- }
- delete _iterator;
- _iterator = NULL;
-}
-
-void SfxPlayer::play_song(SongIterator *it) {
- while (_iterator && _wakeupTime.msecsDiff(_currentTime) <= 0) {
- int delay;
- byte buf[8];
- int result;
-
- switch ((delay = songit_next(&(_iterator),
- buf, &result,
- IT_READER_MASK_ALL
- | IT_READER_MAY_FREE
- | IT_READER_MAY_CLEAN))) {
-
- case SI_FINISHED:
- delete _iterator;
- _iterator = NULL;
- _iteratorIsDone = true;
- return;
-
- case SI_IGNORE:
- case SI_LOOP:
- case SI_RELATIVE_CUE:
- case SI_ABSOLUTE_CUE:
- break;
-
- case SI_PCM:
- sfx_play_iterator_pcm(_iterator, 0);
- break;
-
- case 0:
- static_cast<MidiDriver *>(_mididrv)->send(buf[0], buf[1], buf[2]);
-
- break;
-
- default:
- _wakeupTime = _wakeupTime.addFrames(delay);
- }
- }
-}
-
-void SfxPlayer::tell_synth(int buf_nr, byte *buf) {
- byte op1 = (buf_nr < 2 ? 0 : buf[1]);
- byte op2 = (buf_nr < 3 ? 0 : buf[2]);
-
- static_cast<MidiDriver *>(_mididrv)->send(buf[0], op1, op2);
-}
-
-void SfxPlayer::player_timer_callback(void *refCon) {
- SfxPlayer *thePlayer = (SfxPlayer *)refCon;
- assert(refCon);
- Common::StackLock lock(thePlayer->_mutex);
-
- if (thePlayer->_iterator && !thePlayer->_iteratorIsDone && !thePlayer->_paused) {
- thePlayer->play_song(thePlayer->_iterator);
- }
-
- thePlayer->_currentTime = thePlayer->_currentTime.addFrames(1);
-}
-
-/* API implementation */
-
-Common::Error SfxPlayer::init(ResourceManager *resMan, int expected_latency) {
- MidiDriverType musicDriver = MidiDriver::detectMusicDriver(MDT_PCSPK | MDT_ADLIB);
-
- switch (musicDriver) {
- case MD_ADLIB:
- // FIXME: There's no Amiga sound option, so we hook it up to AdLib
- if (g_sci->getPlatform() == Common::kPlatformAmiga)
- _mididrv = MidiPlayer_Amiga_create(_soundVersion);
- else
- _mididrv = MidiPlayer_AdLib_create(_soundVersion);
- break;
- case MD_PCJR:
- _mididrv = MidiPlayer_PCJr_create(_soundVersion);
- break;
- case MD_PCSPK:
- _mididrv = MidiPlayer_PCSpeaker_create(_soundVersion);
- break;
- default:
- break;
- }
-
- assert(_mididrv);
-
- _polyphony = _mididrv->getPolyphony();
-
- _tempo = _mididrv->getBaseTempo();
- uint32 time = g_system->getMillis();
- _currentTime = Audio::Timestamp(time, 1000000 / _tempo);
- _wakeupTime = Audio::Timestamp(time, SFX_TICKS_PER_SEC);
-
- _mididrv->setTimerCallback(this, player_timer_callback);
- _mididrv->open(resMan);
- _mididrv->setVolume(_volume);
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::add_iterator(SongIterator *it, uint32 start_time) {
- Common::StackLock lock(_mutex);
- SIMSG_SEND(it, SIMSG_SET_PLAYMASK(_mididrv->getPlayId()));
- SIMSG_SEND(it, SIMSG_SET_RHYTHM(_mididrv->hasRhythmChannel()));
-
- if (_iterator == NULL) {
- // Resync with clock
- _currentTime = Audio::Timestamp(g_system->getMillis(), 1000000 / _tempo);
- _wakeupTime = Audio::Timestamp(start_time, SFX_TICKS_PER_SEC);
- }
-
- _iterator = sfx_iterator_combine(_iterator, it);
- _iteratorIsDone = false;
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::stop() {
- debug(3, "Player: Stopping song iterator %p", (void *)_iterator);
- Common::StackLock lock(_mutex);
- delete _iterator;
- _iterator = NULL;
- for (int i = 0; i < MIDI_CHANNELS; i++)
- static_cast<MidiDriver *>(_mididrv)->send(0xb0 + i, SCI_MIDI_CHANNEL_NOTES_OFF, 0);
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::iterator_message(const SongIterator::Message &msg) {
- Common::StackLock lock(_mutex);
- if (!_iterator) {
- return Common::kUnknownError;
- }
-
- songit_handle_message(&_iterator, msg);
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::pause() {
- Common::StackLock lock(_mutex);
-
- _paused = true;
- _pauseTimeDiff = _wakeupTime.msecsDiff(_currentTime);
-
- _mididrv->playSwitch(false);
-
- return Common::kNoError;
-}
-
-Common::Error SfxPlayer::resume() {
- Common::StackLock lock(_mutex);
-
- _wakeupTime = Audio::Timestamp(_currentTime.msecs() + _pauseTimeDiff, SFX_TICKS_PER_SEC);
- _mididrv->playSwitch(true);
- _paused = false;
-
- return Common::kNoError;
-}
-
-void SfxPlayer::setVolume(int vol) {
- _mididrv->setVolume(vol);
-}
-
-int SfxPlayer::getVolume() {
- return _mididrv->getVolume();
-}
-
-#pragma mark -
-
-void SfxState::sfx_reset_player() {
- if (_player)
- _player->stop();
-}
-
-void SfxState::sfx_player_tell_synth(int buf_nr, byte *buf) {
- if (_player)
- _player->tell_synth(buf_nr, buf);
-}
-
-int SfxState::sfx_get_player_polyphony() {
- if (_player)
- return _player->_polyphony;
- else
- return 0;
-}
-
-SfxState::SfxState() {
- _player = NULL;
- _it = NULL;
- _flags = 0;
- _song = NULL;
- _suspended = 0;
-}
-
-SfxState::~SfxState() {
-}
-
-
-void SfxState::freezeTime() {
- /* Freezes the top song delay time */
- const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
- Song *song = _song;
-
- while (song) {
- song->_delay = song->_wakeupTime.frameDiff(ctime);
- if (song->_delay < 0)
- song->_delay = 0;
-
- song = song->_nextPlaying;
- }
-}
-
-void SfxState::thawTime() {
- /* inverse of freezeTime() */
- const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
- Song *song = _song;
-
- while (song) {
- song->_wakeupTime = ctime.addFrames(song->_delay);
-
- song = song->_nextPlaying;
- }
-}
-
-#if 0
-// Unreferenced - removed
-static void _dump_playing_list(SfxState *self, char *msg) {
- Song *song = self->_song;
-
- fprintf(stderr, "[] Song list : [ ");
- song = *(self->_songlib.lib);
- while (song) {
- fprintf(stderr, "%08lx:%d ", song->handle, song->_status);
- song = song->_nextPlaying;
- }
- fprintf(stderr, "]\n");
-
- fprintf(stderr, "[] Play list (%s) : [ " , msg);
-
- while (song) {
- fprintf(stderr, "%08lx ", song->handle);
- song = song->_nextPlaying;
- }
-
- fprintf(stderr, "]\n");
-}
-#endif
-
-#if 0
-static void _dump_songs(SfxState *self) {
- Song *song = self->_song;
-
- fprintf(stderr, "Cue iterators:\n");
- song = *(self->_songlib.lib);
- while (song) {
- fprintf(stderr, " **\tHandle %08x (p%d): status %d\n",
- song->handle, song->_priority, song->_status);
- SIMSG_SEND(song->_it, SIMSG_PRINT(1));
- song = song->_next;
- }
-
- if (self->_player) {
- fprintf(stderr, "Audio iterator:\n");
- self->_player->iterator_message(SongIterator::Message(0, SIMSG_PRINT(1)));
- }
-}
-#endif
-
-bool SfxState::isPlaying(Song *song) {
- Song *playing_song = _song;
-
- /* _dump_playing_list(this, "is-playing");*/
-
- while (playing_song) {
- if (playing_song == song)
- return true;
- playing_song = playing_song->_nextPlaying;
- }
- return false;
-}
-
-void SfxState::setSongStatus(Song *song, int status) {
- const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
-
- switch (status) {
-
- case SOUND_STATUS_STOPPED:
- // Reset
- song->_it->init();
- break;
-
- case SOUND_STATUS_SUSPENDED:
- case SOUND_STATUS_WAITING:
- if (song->_status == SOUND_STATUS_PLAYING) {
- // Update delay, set wakeup_time
- song->_delay += song->_wakeupTime.frameDiff(ctime);
- song->_wakeupTime = ctime;
- }
- if (status == SOUND_STATUS_SUSPENDED)
- break;
-
- /* otherwise... */
-
- case SOUND_STATUS_PLAYING:
- if (song->_status == SOUND_STATUS_STOPPED) {
- // Starting anew
- song->_wakeupTime = ctime;
- }
-
- if (isPlaying(song))
- status = SOUND_STATUS_PLAYING;
- else
- status = SOUND_STATUS_WAITING;
- break;
-
- default:
- fprintf(stderr, "%s L%d: Attempt to set invalid song"
- " state %d!\n", __FILE__, __LINE__, status);
- return;
-
- }
- song->_status = status;
-}
-
-/* Update internal state iff only one song may be played */
-void SfxState::updateSingleSong() {
- Song *newsong = _songlib.findFirstActive();
-
- if (newsong != _song) {
- freezeTime(); /* Store song delay time */
-
- if (_player)
- _player->stop();
-
- if (newsong) {
- if (!newsong->_it)
- return; /* Restore in progress and not ready for this yet */
-
- /* Change song */
- if (newsong->_status == SOUND_STATUS_WAITING)
- setSongStatus(newsong, SOUND_STATUS_PLAYING);
-
- /* Change instrument mappings */
- } else {
- /* Turn off sound */
- }
- if (_song) {
- if (_song->_status == SOUND_STATUS_PLAYING)
- setSongStatus(newsong, SOUND_STATUS_WAITING);
- }
-
- Common::String debugMessage = "[SFX] Changing active song:";
- if (!_song) {
- debugMessage += " New song:";
- } else {
- char tmp[50];
- sprintf(tmp, " pausing %08lx, now playing ", _song->_handle);
- debugMessage += tmp;
- }
-
- if (newsong) {
- char tmp[20];
- sprintf(tmp, "%08lx\n", newsong->_handle);
- debugMessage += tmp;
- } else {
- debugMessage += " none\n";
- }
-
- debugC(2, kDebugLevelSound, "%s", debugMessage.c_str());
-
- _song = newsong;
- thawTime(); /* Recover song delay time */
-
- if (newsong && _player) {
- SongIterator *clonesong = newsong->_it->clone(newsong->_delay);
-
- _player->add_iterator(clonesong, newsong->_wakeupTime.msecs());
- }
- }
-}
-
-
-void SfxState::updateMultiSong() {
- Song *oldfirst = _song;
- Song *oldseeker;
- Song *newsong = _songlib.findFirstActive();
- Song *newseeker;
- Song not_playing_anymore; /* Dummy object, referenced by
- ** songs which are no longer
- ** active. */
-
- /* _dump_playing_list(this, "before");*/
- freezeTime(); /* Store song delay time */
-
- // WORKAROUND: sometimes, newsong can be NULL (e.g. in SQ4).
- // Handle this here, so that we avoid a crash
- if (!newsong) {
- // Iterators should get freed when there's only one song left playing
- if(oldfirst && oldfirst->_status == SOUND_STATUS_STOPPED) {
- debugC(2, kDebugLevelSound, "[SFX] Stopping song %lx", oldfirst->_handle);
- if (_player && oldfirst->_it)
- _player->iterator_message(SongIterator::Message(oldfirst->_it->ID, SIMSG_STOP));
- }
- return;
- }
-
- for (newseeker = newsong; newseeker;
- newseeker = newseeker->_nextPlaying) {
- if (!newseeker || !newseeker->_it)
- return; /* Restore in progress and not ready for this yet */
- }
-
- /* First, put all old songs into the 'stopping' list and
- ** mark their 'next-playing' as not_playing_anymore. */
- for (oldseeker = oldfirst; oldseeker;
- oldseeker = oldseeker->_nextStopping) {
- oldseeker->_nextStopping = oldseeker->_nextPlaying;
- oldseeker->_nextPlaying = &not_playing_anymore;
-
- if (oldseeker == oldseeker->_nextPlaying) {
- error("updateMultiSong() failed. Breakpoint in %s, line %d", __FILE__, __LINE__);
- }
- }
-
- /* Second, re-generate the new song queue. */
- for (newseeker = newsong; newseeker; newseeker = newseeker->_nextPlaying) {
- newseeker->_nextPlaying = _songlib.findNextActive(newseeker);
-
- if (newseeker == newseeker->_nextPlaying) {
- error("updateMultiSong() failed. Breakpoint in %s, line %d", __FILE__, __LINE__);
- }
- }
- /* We now need to update the currently playing song list, because we're
- ** going to use some functions that require this list to be in a sane
- ** state (particularly isPlaying(), indirectly */
- _song = newsong;
-
- /* Third, stop all old songs */
- for (oldseeker = oldfirst; oldseeker;
- oldseeker = oldseeker->_nextStopping)
- if (oldseeker->_nextPlaying == &not_playing_anymore) {
- setSongStatus(oldseeker, SOUND_STATUS_SUSPENDED);
- debugC(2, kDebugLevelSound, "[SFX] Stopping song %lx", oldseeker->_handle);
-
- if (_player && oldseeker->_it)
- _player->iterator_message(SongIterator::Message(oldseeker->_it->ID, SIMSG_STOP));
- oldseeker->_nextPlaying = NULL; /* Clear this pointer; we don't need the tag anymore */
- }
-
- for (newseeker = newsong; newseeker; newseeker = newseeker->_nextPlaying) {
- if (newseeker->_status != SOUND_STATUS_PLAYING && _player) {
- debugC(2, kDebugLevelSound, "[SFX] Adding song %lx", newseeker->_it->ID);
-
- SongIterator *clonesong = newseeker->_it->clone(newseeker->_delay);
- _player->add_iterator(clonesong, g_system->getMillis());
- }
- setSongStatus(newseeker, SOUND_STATUS_PLAYING);
- }
-
- _song = newsong;
- thawTime();
- /* _dump_playing_list(this, "after");*/
-}
-
-/* Update internal state */
-void SfxState::update() {
- if (_flags & SFX_STATE_FLAG_MULTIPLAY)
- updateMultiSong();
- else
- updateSingleSong();
-}
-
-static int sfx_play_iterator_pcm(SongIterator *it, SongHandle handle) {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Playing PCM: %08lx\n", handle);
-#endif
- if (g_system->getMixer()->isReady()) {
- Audio::AudioStream *newfeed = it->getAudioStream();
- if (newfeed) {
- g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, 0, newfeed);
- return 1;
- }
- }
- return 0;
-}
-
-#define DELAY (1000000 / SFX_TICKS_PER_SEC)
-
-void SfxState::sfx_init(ResourceManager *resMan, int flags, SciVersion soundVersion) {
- _songlib._lib = 0;
- _song = NULL;
- _flags = flags;
-
- _player = NULL;
-
- if (flags & SFX_STATE_FLAG_NOSOUND) {
- warning("[SFX] Sound disabled");
- return;
- }
-
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Initialising: flags=%x\n", flags);
-#endif
-
- /*-------------------*/
- /* Initialise player */
- /*-------------------*/
-
- if (!resMan) {
- warning("[SFX] Warning: No resource manager present, cannot initialise player");
- return;
- }
-
- _player = new SfxPlayer(soundVersion);
-
- if (!_player) {
- warning("[SFX] No song player found");
- return;
- }
-
- if (_player->init(resMan, DELAY / 1000)) {
- warning("[SFX] Song player reported error, disabled");
- delete _player;
- _player = NULL;
- }
-
- _resMan = resMan;
-}
-
-void SfxState::sfx_exit() {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Uninitialising\n");
-#endif
-
- delete _player;
- _player = 0;
-
- g_system->getMixer()->stopAll();
-
- _songlib.freeSounds();
-}
-
-void SfxState::sfx_suspend(bool suspend) {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Suspending? = %d\n", suspend);
-#endif
- if (suspend && (!_suspended)) {
- /* suspend */
-
- freezeTime();
- if (_player)
- _player->pause();
- /* Suspend song player */
-
- } else if (!suspend && (_suspended)) {
- /* unsuspend */
-
- thawTime();
- if (_player)
- _player->resume();
-
- /* Unsuspend song player */
- }
-
- _suspended = suspend;
-}
-
-int SfxState::sfx_poll(SongHandle *handle, int *cue) {
- if (!_song)
- return 0; /* No milk today */
-
- *handle = _song->_handle;
-
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Polling any (%08lx)\n", *handle);
-#endif
- return sfx_poll_specific(*handle, cue);
-}
-
-int SfxState::sfx_poll_specific(SongHandle handle, int *cue) {
- const Audio::Timestamp ctime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
- Song *song = _song;
-
- while (song && song->_handle != handle)
- song = song->_nextPlaying;
-
- if (!song)
- return 0; /* Song not playing */
-
- debugC(2, kDebugLevelSound, "[SFX:CUE] Polled song %08lx ", handle);
-
- while (1) {
- if (song->_wakeupTime.frameDiff(ctime) > 0)
- return 0; /* Patience, young hacker! */
-
- byte buf[8];
- int result = songit_next(&(song->_it), buf, cue, IT_READER_MASK_ALL);
-
- switch (result) {
-
- case SI_FINISHED:
- setSongStatus(song, SOUND_STATUS_STOPPED);
- update();
- /* ...fall through... */
- case SI_LOOP:
- case SI_RELATIVE_CUE:
- case SI_ABSOLUTE_CUE:
- if (result == SI_FINISHED)
- debugC(2, kDebugLevelSound, " => finished");
- else {
- if (result == SI_LOOP)
- debugC(2, kDebugLevelSound, " => Loop: %d (0x%x)", *cue, *cue);
- else
- debugC(2, kDebugLevelSound, " => Cue: %d (0x%x)", *cue, *cue);
-
- }
- return result;
-
- default:
- if (result > 0)
- song->_wakeupTime = song->_wakeupTime.addFrames(result);
-
- /* Delay */
- break;
- }
- }
-
-}
-
-
-/*****************/
-/* Song basics */
-/*****************/
-
-void SfxState::sfx_add_song(SongIterator *it, int priority, SongHandle handle, int number) {
- Song *song = _songlib.findSong(handle);
-
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Adding song: %08lx at %d, it=%p\n", handle, priority, it);
-#endif
- if (!it) {
- error("[SFX] Attempt to add empty song with handle %08lx", handle);
- return;
- }
-
- it->init();
-
- /* If we're already playing this, stop it */
- /* Tell player to shut up */
-// _dump_songs(this);
-
- if (_player)
- _player->iterator_message(SongIterator::Message(handle, SIMSG_STOP));
-
- if (song) {
- setSongStatus( song, SOUND_STATUS_STOPPED);
-
- fprintf(stderr, "Overwriting old song (%08lx) ...\n", handle);
- if (song->_status == SOUND_STATUS_PLAYING || song->_status == SOUND_STATUS_SUSPENDED) {
- delete it;
- error("Unexpected (error): Song %ld still playing/suspended (%d)",
- handle, song->_status);
- return;
- } else {
- _songlib.removeSong(handle); /* No duplicates */
- }
-
- }
-
- song = new Song(handle, it, priority);
- song->_resourceNum = number;
- song->_hold = 0;
- song->_loops = 0;
- song->_wakeupTime = Audio::Timestamp(g_system->getMillis(), SFX_TICKS_PER_SEC);
- _songlib.addSong(song);
- _song = NULL; /* As above */
- update();
-
- return;
-}
-
-void SfxState::sfx_remove_song(SongHandle handle) {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Removing song: %08lx\n", handle);
-#endif
- if (_song && _song->_handle == handle)
- _song = NULL;
-
- _songlib.removeSong(handle);
- update();
-}
-
-
-
-/**********************/
-/* Song modifications */
-/**********************/
-
-#define ASSERT_SONG(s) if (!(s)) { warning("Looking up song handle %08lx failed in %s, L%d", handle, __FILE__, __LINE__); return; }
-
-void SfxState::sfx_song_set_status(SongHandle handle, int status) {
- Song *song = _songlib.findSong(handle);
- ASSERT_SONG(song);
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Setting song status to %d"
- " (0:stop, 1:play, 2:susp, 3:wait): %08lx\n", status, handle);
-#endif
-
- setSongStatus(song, status);
-
- update();
-}
-
-void SfxState::sfx_song_set_fade(SongHandle handle, fade_params_t *params) {
-#ifdef DEBUG_SONG_API
- static const char *stopmsg[] = {"??? Should not happen", "Do not stop afterwards", "Stop afterwards"};
-#endif
- Song *song = _songlib.findSong(handle);
-
- ASSERT_SONG(song);
-
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Setting fade params of %08lx to "
- "final volume %d in steps of %d per %d ticks. %s.",
- handle, fade->final_volume, fade->step_size, fade->ticks_per_step,
- stopmsg[fade->action]);
-#endif
-
- SIMSG_SEND_FADE(song->_it, params);
-
- update();
-}
-
-void SfxState::sfx_song_renice(SongHandle handle, int priority) {
- Song *song = _songlib.findSong(handle);
- ASSERT_SONG(song);
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Renicing song %08lx to %d\n",
- handle, priority);
-#endif
-
- song->_priority = priority;
-
- update();
-}
-
-void SfxState::sfx_song_set_loops(SongHandle handle, int loops) {
- Song *song = _songlib.findSong(handle);
- SongIterator::Message msg = SongIterator::Message(handle, SIMSG_SET_LOOPS(loops));
- ASSERT_SONG(song);
-
- song->_loops = loops;
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Setting loops on %08lx to %d\n",
- handle, loops);
-#endif
- songit_handle_message(&(song->_it), msg);
-
- if (_player/* && _player->send_iterator_message*/)
- /* FIXME: The above should be optional! */
- _player->iterator_message(msg);
-}
-
-void SfxState::sfx_song_set_hold(SongHandle handle, int hold) {
- Song *song = _songlib.findSong(handle);
- SongIterator::Message msg = SongIterator::Message(handle, SIMSG_SET_HOLD(hold));
- ASSERT_SONG(song);
-
- song->_hold = hold;
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] Setting hold on %08lx to %d\n",
- handle, hold);
-#endif
- songit_handle_message(&(song->_it), msg);
-
- if (_player/* && _player->send_iterator_message*/)
- /* FIXME: The above should be optional! */
- _player->iterator_message(msg);
-}
-
-/* Different from the one in iterator.c */
-static const int MIDI_cmdlen[16] = {0, 0, 0, 0, 0, 0, 0, 0,
- 3, 3, 0, 3, 2, 0, 3, 0
- };
-
-static const SongHandle midi_send_base = 0xffff0000;
-
-Common::Error SfxState::sfx_send_midi(SongHandle handle, int channel,
- int command, int arg1, int arg2) {
- byte buffer[5];
-
- /* Yes, in that order. SCI channel mutes are actually done via
- a counting semaphore. 0 means to decrement the counter, 1
- to increment it. */
- static const char *channel_state[] = {"ON", "OFF"};
-
- if (command == 0xb0 &&
- arg1 == SCI_MIDI_CHANNEL_MUTE) {
- warning("TODO: channel mute (channel %d %s)", channel, channel_state[arg2]);
- /* We need to have a GET_PLAYMASK interface to use
- here. SET_PLAYMASK we've got.
- */
- return Common::kNoError;
- }
-
- buffer[0] = channel | command; /* No channel remapping yet */
-
- switch (command) {
- case 0x80 :
- case 0x90 :
- case 0xb0 :
- buffer[1] = arg1 & 0xff;
- buffer[2] = arg2 & 0xff;
- break;
- case 0xc0 :
- buffer[1] = arg1 & 0xff;
- break;
- case 0xe0 :
- buffer[1] = (arg1 & 0x7f) | 0x80;
- buffer[2] = (arg1 & 0xff00) >> 7;
- break;
- default:
- warning("Unexpected explicit MIDI command %02x", command);
- return Common::kUnknownError;
- }
-
- if (_player)
- _player->tell_synth(MIDI_cmdlen[command >> 4], buffer);
- return Common::kNoError;
-}
-
-int SfxState::sfx_getVolume() {
- return _player->getVolume();
-}
-
-void SfxState::sfx_setVolume(int volume) {
- _player->setVolume(volume);
-}
-
-void SfxState::sfx_all_stop() {
-#ifdef DEBUG_SONG_API
- fprintf(stderr, "[sfx-core] All stop\n");
-#endif
-
- _songlib.freeSounds();
- update();
-}
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
diff --git a/engines/sci/sound/iterator/core.h b/engines/sci/sound/iterator/core.h
deleted file mode 100644
index a44fe2ecae..0000000000
--- a/engines/sci/sound/iterator/core.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/* Sound engine */
-#ifndef SCI_SFX_CORE_H
-#define SCI_SFX_CORE_H
-
-#include "common/error.h"
-
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#include "sci/sound/iterator/songlib.h"
-#include "sci/resource.h"
-
-namespace Sci {
-
-class SfxPlayer;
-class SongIterator;
-struct fade_params_t;
-
-#define SFX_TICKS_PER_SEC 60 /* MIDI ticks per second */
-
-
-#define SFX_STATE_FLAG_MULTIPLAY (1 << 0) /* More than one song playable
-** simultaneously ? */
-#define SFX_STATE_FLAG_NOSOUND (1 << 1) /* Completely disable sound playing */
-
-class SfxState {
-private:
- SfxPlayer *_player;
-
-public: // FIXME, make private
- SongIterator *_it; /**< The song iterator at the heart of things */
- uint _flags; /**< SFX_STATE_FLAG_* */
- SongLibrary _songlib; /**< Song library */
- Song *_song; /**< Active song, or start of active song chain */
- bool _suspended; /**< Whether we are suspended */
- ResourceManager *_resMan;
-
-public:
- SfxState();
- ~SfxState();
-
- /***********/
- /* General */
- /***********/
-
- /* Initializes the sound engine
- ** Parameters: (ResourceManager *) resMan: Resource manager for initialization
- ** (int) flags: SFX_STATE_FLAG_*
- */
- void sfx_init(ResourceManager *resMan, int flags, SciVersion soundVersion);
-
- /** Deinitializes the sound subsystem. */
- void sfx_exit();
-
- /* Suspends/unsuspends the sound sybsystem
- ** Parameters: (int) suspend: Whether to suspend (non-null) or to unsuspend
- */
- void sfx_suspend(bool suspend);
-
- /* Polls the sound server for cues etc.
- ** Returns : (int) 0 if the cue queue is empty, SI_LOOP, SI_CUE, or SI_FINISHED otherwise
- ** (SongHandle) *handle: The affected handle
- ** (int) *cue: The sound cue number (if SI_CUE), or the loop number (if SI_LOOP)
- */
- int sfx_poll(SongHandle *handle, int *cue);
-
- /* Polls the sound server for cues etc.
- ** Parameters: (SongHandle) handle: The handle to poll
- ** Returns : (int) 0 if the cue queue is empty, SI_LOOP, SI_CUE, or SI_FINISHED otherwise
- ** (int) *cue: The sound cue number (if SI_CUE), or the loop number (if SI_LOOP)
- */
- int sfx_poll_specific(SongHandle handle, int *cue);
-
- /* Determines the current global volume settings
- ** Returns : (int) The global volume, between 0 (silent) and 127 (max. volume)
- */
- int sfx_getVolume();
-
- /* Determines the current global volume settings
- ** Parameters: (int) volume: The new global volume, between 0 and 127 (see above)
- */
- void sfx_setVolume(int volume);
-
- /* Stops all songs currently playing, purges song library
- */
- void sfx_all_stop();
-
-
- /*****************/
- /* Song basics */
- /*****************/
-
- /* Adds a song to the internal sound library
- ** Parameters: (SongIterator *) it: The iterator describing the song
- ** (int) priority: Initial song priority (higher <-> more important)
- ** (SongHandle) handle: The handle to associate with the song
- */
- void sfx_add_song(SongIterator *it, int priority, SongHandle handle, int resnum);
-
-
- /* Deletes a song and its associated song iterator from the song queue
- ** Parameters: (SongHandle) handle: The song to remove
- */
- void sfx_remove_song(SongHandle handle);
-
-
- /**********************/
- /* Song modifications */
- /**********************/
-
-
- /* Sets the song status, i.e. whether it is playing, suspended, or stopped.
- ** Parameters: (SongHandle) handle: Handle of the song to modify
- ** (int) status: The song status the song should assume
- ** WAITING and PLAYING are set implicitly and essentially describe the same state
- ** as far as this function is concerned.
- */
- void sfx_song_set_status(SongHandle handle, int status);
-
- /* Sets the new song priority
- ** Parameters: (SongHandle) handle: The handle to modify
- ** (int) priority: The priority to set
- */
- void sfx_song_renice(SongHandle handle, int priority);
-
- /* Sets the number of loops for the specified song
- ** Parameters: (SongHandle) handle: The song handle to reference
- ** (int) loops: Number of loops to set
- */
- void sfx_song_set_loops(SongHandle handle, int loops);
-
- /* Sets the number of loops for the specified song
- ** Parameters: (SongHandle) handle: The song handle to reference
- ** (int) hold: Number of loops to setn
- */
- void sfx_song_set_hold(SongHandle handle, int hold);
-
- /* Instructs a song to be faded out
- ** Parameters: (SongHandle) handle: The song handle to reference
- ** (fade_params_t *) fade_setup: The precise fade-out configuration to use
- */
- void sfx_song_set_fade(SongHandle handle, fade_params_t *fade_setup);
-
-
- // Previously undocumented:
- Common::Error sfx_send_midi(SongHandle handle, int channel,
- int command, int arg1, int arg2);
-
- // misc
-
- /**
- * Determines the polyphony of the player in use.
- * @return Number of voices the active player can emit
- */
- int sfx_get_player_polyphony();
-
- /**
- * Tells the player to stop its internal iterator.
- */
- void sfx_reset_player();
-
- /**
- * Pass a raw MIDI event to the synth of the player.
- * @param argc Length of buffer holding the midi event
- * @param argv The buffer itself
- */
- void sfx_player_tell_synth(int buf_nr, byte *buf);
-
-protected:
- void freezeTime();
- void thawTime();
-
- bool isPlaying(Song *song);
- void setSongStatus(Song *song, int status);
- void updateSingleSong();
- void updateMultiSong();
- void update();
-};
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
-
-#endif // SCI_SFX_CORE_H
diff --git a/engines/sci/sound/iterator/iterator.cpp b/engines/sci/sound/iterator/iterator.cpp
deleted file mode 100644
index 5d9d63e5af..0000000000
--- a/engines/sci/sound/iterator/iterator.cpp
+++ /dev/null
@@ -1,1686 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/* Song iterators */
-
-#include "common/util.h"
-
-#include "sci/sci.h"
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-
-#include "sci/sound/iterator/iterator_internal.h"
-#include "sci/engine/state.h" // for sfx_player_tell_synth :/
-#include "sci/sound/iterator/core.h" // for sfx_player_tell_synth
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-#include "sound/decoders/raw.h"
-
-namespace Sci {
-
-
-static const int MIDI_cmdlen[16] = {0, 0, 0, 0, 0, 0, 0, 0,
- 2, 2, 2, 2, 1, 1, 2, 0
- };
-
-/*#define DEBUG_DECODING*/
-/*#define DEBUG_VERBOSE*/
-
-/** Find first set bit in bits and return its index. Returns 0 if bits is 0. */
-static int sci_ffs(int bits) {
- if (!bits)
- return 0;
-
- int retval = 1;
-
- while (!(bits & 1)) {
- retval++;
- bits >>= 1;
- }
-
- return retval;
-}
-
-static void print_tabs_id(int nr, songit_id_t id) {
- while (nr-- > 0)
- fprintf(stderr, "\t");
-
- fprintf(stderr, "[%08lx] ", id);
-}
-
-BaseSongIterator::BaseSongIterator(byte *data, uint size, songit_id_t id)
- : _data(data, size) {
- ID = id;
-}
-
-/************************************/
-/*-- SCI0 iterator implementation --*/
-/************************************/
-
-#define SCI0_MIDI_OFFSET 33
-#define SCI0_END_OF_SONG 0xfc /* proprietary MIDI command */
-
-#define SCI0_PCM_SAMPLE_RATE_OFFSET 0x0e
-#define SCI0_PCM_SIZE_OFFSET 0x20
-#define SCI0_PCM_DATA_OFFSET 0x2c
-
-#define CHECK_FOR_END_ABSOLUTE(offset) \
- if (offset > _data.size()) { \
- warning("Reached end of song without terminator (%x/%x) at %d", offset, _data.size(), __LINE__); \
- return SI_FINISHED; \
- }
-
-#define CHECK_FOR_END(offset_augment) \
- if ((channel->offset + (offset_augment)) > channel->end) { \
- channel->state = SI_STATE_FINISHED; \
- warning("Reached end of track %d without terminator (%x+%x/%x) at %d", channel->id, channel->offset, offset_augment, channel->end, __LINE__); \
- return SI_FINISHED; \
- }
-
-
-static int _parse_ticks(byte *data, int *offset_p, int size) {
- int ticks = 0;
- int tempticks;
- int offset = 0;
-
- do {
- tempticks = data[offset++];
- ticks += (tempticks == SCI_MIDI_TIME_EXPANSION_PREFIX) ?
- SCI_MIDI_TIME_EXPANSION_LENGTH : tempticks;
- } while (tempticks == SCI_MIDI_TIME_EXPANSION_PREFIX
- && offset < size);
-
- if (offset_p)
- *offset_p = offset;
-
- return ticks;
-}
-
-
-static int _sci0_get_pcm_data(Sci0SongIterator *self, int *rate, int *xoffset, uint *xsize);
-
-
-#define PARSE_FLAG_LOOPS_UNLIMITED (1 << 0) /* Unlimited # of loops? */
-#define PARSE_FLAG_PARAMETRIC_CUE (1 << 1) /* Assume that cues take an additional "cue value" argument */
-/* This implements a difference between SCI0 and SCI1 cues. */
-
-void SongIteratorChannel::init(int id_, int offset_, int end_) {
- playmask = PLAYMASK_NONE; /* Disable all channels */
- id = id_;
- state = SI_STATE_DELTA_TIME;
- loop_timepos = 0;
- total_timepos = 0;
- timepos_increment = 0;
- delay = 0; /* Only used for more than one channel */
- last_cmd = 0xfe;
-
- offset = loop_offset = initial_offset = offset_;
- end = end_;
-}
-
-void SongIteratorChannel::resetSynthChannels() {
- byte buf[5];
-
- // FIXME: Evil hack
- SfxState &sound = g_sci->getEngineState()->_sound;
-
- for (int i = 0; i < MIDI_CHANNELS; i++) {
- if (playmask & (1 << i)) {
- buf[0] = 0xe0 | i; /* Pitch bend */
- buf[1] = 0x80; /* Wheel center */
- buf[2] = 0x40;
- sound.sfx_player_tell_synth(3, buf);
-
- buf[0] = 0xb0 | i; // Set control
- buf[1] = 0x40; // Hold pedal
- buf[2] = 0x00; // Off
- sound.sfx_player_tell_synth(3, buf);
- /* TODO: Reset other controls? */
- }
- }
-}
-
-int BaseSongIterator::parseMidiCommand(byte *buf, int *result, SongIteratorChannel *channel, int flags) {
- byte cmd;
- int paramsleft;
- int midi_op;
- int midi_channel;
-
- channel->state = SI_STATE_DELTA_TIME;
-
- cmd = _data[channel->offset++];
-
- if (!(cmd & 0x80)) {
- /* 'Running status' mode */
- channel->offset--;
- cmd = channel->last_cmd;
- }
-
- if (cmd == 0xfe) {
- warning("song iterator subsystem: Corrupted sound resource detected.");
- return SI_FINISHED;
- }
-
- midi_op = cmd >> 4;
- midi_channel = cmd & 0xf;
- paramsleft = MIDI_cmdlen[midi_op];
-
-#if 0
- if (1) {
- fprintf(stderr, "[IT]: off=%x, cmd=%02x, takes %d args ",
- channel->offset - 1, cmd, paramsleft);
- fprintf(stderr, "[%02x %02x <%02x> %02x %02x %02x]\n",
- _data[channel->offset-3],
- _data[channel->offset-2],
- _data[channel->offset-1],
- _data[channel->offset],
- _data[channel->offset+1],
- _data[channel->offset+2]);
- }
-#endif
-
- buf[0] = cmd;
-
-
- CHECK_FOR_END(paramsleft);
- memcpy(buf + 1, _data.begin() + channel->offset, paramsleft);
- *result = 1 + paramsleft;
-
- channel->offset += paramsleft;
-
- channel->last_cmd = cmd;
-
- /* Are we supposed to play this channel? */
- if (
- /* First, exclude "global" properties-- such as cues-- from consideration */
- (midi_op < 0xf
- && !(cmd == SCI_MIDI_SET_SIGNAL)
- && !(SCI_MIDI_CONTROLLER(cmd)
- && buf[1] == SCI_MIDI_CUMULATIVE_CUE))
-
- /* Next, check if the channel is allowed */
- && (!((1 << midi_channel) & channel->playmask)))
- return /* Execute next command */
- nextCommand(buf, result);
-
-
- if (cmd == SCI_MIDI_EOT) {
- /* End of track? */
- channel->resetSynthChannels();
- if (_loops > 1) {
- /* If allowed, decrement the number of loops */
- if (!(flags & PARSE_FLAG_LOOPS_UNLIMITED))
- *result = --_loops;
-
-#ifdef DEBUG_DECODING
- fprintf(stderr, "%s L%d: (%p):%d Looping ", __FILE__, __LINE__, this, channel->id);
- if (flags & PARSE_FLAG_LOOPS_UNLIMITED)
- fprintf(stderr, "(indef.)");
- else
- fprintf(stderr, "(%d)", _loops);
- fprintf(stderr, " %x -> %x\n",
- channel->offset, channel->loop_offset);
-#endif
- channel->offset = channel->loop_offset;
- channel->state = SI_STATE_DELTA_TIME;
- channel->total_timepos = channel->loop_timepos;
- channel->last_cmd = 0xfe;
- debugC(2, kDebugLevelSound, "Looping song iterator %08lx.", ID);
- return SI_LOOP;
- } else {
- channel->state = SI_STATE_FINISHED;
- return SI_FINISHED;
- }
-
- } else if (cmd == SCI_MIDI_SET_SIGNAL) {
- if (buf[1] == SCI_MIDI_SET_SIGNAL_LOOP) {
- channel->loop_offset = channel->offset;
- channel->loop_timepos = channel->total_timepos;
-
- return /* Execute next command */
- nextCommand(buf, result);
- } else {
- /* Used to be conditional <= 127 */
- *result = buf[1]; /* Absolute cue */
- return SI_ABSOLUTE_CUE;
- }
- } else if (SCI_MIDI_CONTROLLER(cmd)) {
- switch (buf[1]) {
-
- case SCI_MIDI_CUMULATIVE_CUE:
- if (flags & PARSE_FLAG_PARAMETRIC_CUE)
- _ccc += buf[2];
- else { /* No parameter to CC */
- _ccc++;
- /* channel->offset--; */
- }
- *result = _ccc;
- return SI_RELATIVE_CUE;
-
- case SCI_MIDI_RESET_ON_SUSPEND:
- _resetflag = buf[2];
- break;
-
- case SCI_MIDI_SET_POLYPHONY:
- _polyphony[midi_channel] = buf[2];
-
-#if 0
- {
- Sci1SongIterator *self1 = (Sci1SongIterator *)this;
- int i;
- int voices = 0;
- for (i = 0; i < self1->_numChannels; i++) {
- voices += _polyphony[i];
- }
-
- printf("SET_POLYPHONY(%d, %d) for a total of %d voices\n", midi_channel, buf[2], voices);
- printf("[iterator] DEBUG: Polyphony = [ ");
- for (i = 0; i < self1->_numChannels; i++)
- printf("%d ", _polyphony[i]);
- printf("]\n");
- printf("[iterator] DEBUG: Importance = [ ");
- printf("]\n");
- }
-#endif
- break;
-
- case SCI_MIDI_SET_REVERB:
- break;
-
- case SCI_MIDI_CHANNEL_MUTE:
- warning("CHANNEL_MUTE(%d, %d)", midi_channel, buf[2]);
- break;
-
- case SCI_MIDI_HOLD: {
- // Safe cast: This controller is only used in SCI1
- Sci1SongIterator *self1 = (Sci1SongIterator *)this;
-
- if (buf[2] == self1->_hold) {
- channel->offset = channel->initial_offset;
- channel->state = SI_STATE_COMMAND;
- channel->total_timepos = 0;
-
- self1->_numLoopedChannels = self1->_numActiveChannels - 1;
-
- // FIXME:
- // This implementation of hold breaks getting out of the
- // limo when visiting the airport near the start of LSL5.
- // It seems like all channels should be reset here somehow,
- // but not sure how.
- // Forcing all channel offsets to 0 seems to fix the hang,
- // but somehow slows the exit sequence down to take 20 seconds
- // instead of about 3.
-
- return SI_LOOP;
- }
-
- break;
- }
- case 0x04: /* UNKNOWN NYI (happens in LSL2 gameshow) */
- case 0x46: /* UNKNOWN NYI (happens in LSL3 binoculars) */
- case 0x61: /* UNKNOWN NYI (special for AdLib? Iceman) */
- case 0x73: /* UNKNOWN NYI (happens in Hoyle) */
- case 0xd1: /* UNKNOWN NYI (happens in KQ4 when riding the unicorn) */
- return /* Execute next command */
- nextCommand(buf, result);
-
- case 0x01: /* modulation */
- case 0x07: /* volume */
- case 0x0a: /* panpot */
- case 0x0b: /* expression */
- case 0x40: /* hold */
- case 0x79: /* reset all */
- /* No special treatment neccessary */
- break;
-
- }
- return 0;
-
- } else {
-#if 0
- /* Perform remapping, if neccessary */
- if (cmd != SCI_MIDI_SET_SIGNAL
- && cmd < 0xf0) { /* Not a generic command */
- int chan = cmd & 0xf;
- int op = cmd & 0xf0;
-
- chan = channel_remap[chan];
- buf[0] = chan | op;
- }
-#endif
-
- /* Process as normal MIDI operation */
- return 0;
- }
-}
-
-int BaseSongIterator::processMidi(byte *buf, int *result,
- SongIteratorChannel *channel, int flags) {
- CHECK_FOR_END(0);
-
- switch (channel->state) {
-
- case SI_STATE_PCM: {
- if (_data[channel->offset] == 0
- && _data[channel->offset + 1] == SCI_MIDI_EOT)
- /* Fake one extra tick to trick the interpreter into not killing the song iterator right away */
- channel->state = SI_STATE_PCM_MAGIC_DELTA;
- else
- channel->state = SI_STATE_DELTA_TIME;
- return SI_PCM;
- }
-
- case SI_STATE_PCM_MAGIC_DELTA: {
- int rate;
- int offset;
- uint size;
- int delay;
- if (_sci0_get_pcm_data((Sci0SongIterator *)this, &rate, &offset, &size))
- return SI_FINISHED; /* 'tis broken */
- channel->state = SI_STATE_FINISHED;
- delay = (size * 50 + rate - 1) / rate; /* number of ticks to completion*/
-
- debugC(2, kDebugLevelSound, "delaying %d ticks", delay);
- return delay;
- }
-
- case SI_STATE_UNINITIALISED:
- warning("Attempt to read command from uninitialized iterator");
- init();
- return nextCommand(buf, result);
-
- case SI_STATE_FINISHED:
- return SI_FINISHED;
-
- case SI_STATE_DELTA_TIME: {
- int offset;
- int ticks = _parse_ticks(_data.begin() + channel->offset,
- &offset,
- _data.size() - channel->offset);
-
- channel->offset += offset;
- channel->delay += ticks;
- channel->timepos_increment = ticks;
-
- CHECK_FOR_END(0);
-
- channel->state = SI_STATE_COMMAND;
-
- if (ticks)
- return ticks;
- }
-
- /* continute otherwise... */
-
- case SI_STATE_COMMAND: {
- int retval;
- channel->total_timepos += channel->timepos_increment;
- channel->timepos_increment = 0;
-
- retval = parseMidiCommand(buf, result, channel, flags);
-
- if (retval == SI_FINISHED) {
- if (_numActiveChannels)
- --(_numActiveChannels);
-#ifdef DEBUG_DECODING
- fprintf(stderr, "%s L%d: (%p):%d Finished channel, %d channels left\n",
- __FILE__, __LINE__, this, channel->id,
- _numActiveChannels);
-#endif
- /* If we still have channels left... */
- if (_numActiveChannels) {
- return nextCommand(buf, result);
- }
-
- /* Otherwise, we have reached the end */
- _loops = 0;
- }
-
- return retval;
- }
-
- default:
- error("Invalid iterator state %d", channel->state);
- return SI_FINISHED;
- }
-}
-
-int Sci0SongIterator::nextCommand(byte *buf, int *result) {
- return processMidi(buf, result, &_channel, PARSE_FLAG_PARAMETRIC_CUE);
-}
-
-static int _sci0_header_magic_p(byte *data, int offset, int size) {
- if (offset + 0x10 > size)
- return 0;
- return (data[offset] == 0x1a)
- && (data[offset + 1] == 0x00)
- && (data[offset + 2] == 0x01)
- && (data[offset + 3] == 0x00);
-}
-
-
-static int _sci0_get_pcm_data(Sci0SongIterator *self,
- int *rate, int *xoffset, uint *xsize) {
- int tries = 2;
- bool found_it = false;
- byte *pcm_data;
- int size;
- uint offset = SCI0_MIDI_OFFSET;
-
- if (self->_data[0] != 2)
- return 1;
- /* No such luck */
-
- while ((tries--) && (offset < self->_data.size()) && (!found_it)) {
- // Search through the garbage manually
- // FIXME: Replace offset by an iterator
- Common::Array<byte>::iterator iter = Common::find(self->_data.begin() + offset, self->_data.end(), SCI0_END_OF_SONG);
-
- if (iter == self->_data.end()) {
- warning("Playing unterminated song");
- return 1;
- }
-
- // add one to move it past the END_OF_SONG marker
- iter++;
- offset = iter - self->_data.begin(); // FIXME
-
-
- if (_sci0_header_magic_p(self->_data.begin(), offset, self->_data.size()))
- found_it = true;
- }
-
- if (!found_it) {
- warning("Song indicates presence of PCM, but"
- " none found (finally at offset %04x)", offset);
-
- return 1;
- }
-
- pcm_data = self->_data.begin() + offset;
-
- size = READ_LE_UINT16(pcm_data + SCI0_PCM_SIZE_OFFSET);
-
- /* Two of the format parameters are fixed by design: */
- *rate = READ_LE_UINT16(pcm_data + SCI0_PCM_SAMPLE_RATE_OFFSET);
-
- if (offset + SCI0_PCM_DATA_OFFSET + size != self->_data.size()) {
- int d = offset + SCI0_PCM_DATA_OFFSET + size - self->_data.size();
-
- warning("PCM advertizes %d bytes of data, but %d"
- " bytes are trailing in the resource",
- size, self->_data.size() - (offset + SCI0_PCM_DATA_OFFSET));
-
- if (d > 0)
- size -= d; /* Fix this */
- }
-
- *xoffset = offset;
- *xsize = size;
-
- return 0;
-}
-
-static Audio::AudioStream *makeStream(byte *data, int size, int rate) {
- debugC(2, kDebugLevelSound, "Playing PCM data of size %d, rate %d", size, rate);
-
- // Duplicate the data
- byte *sound = (byte *)malloc(size);
- memcpy(sound, data, size);
-
- // Convert stream format flags
- int flags = Audio::FLAG_UNSIGNED;
- return Audio::makeRawStream(sound, size, rate, flags);
-}
-
-Audio::AudioStream *Sci0SongIterator::getAudioStream() {
- int rate;
- int offset;
- uint size;
- if (_sci0_get_pcm_data(this, &rate, &offset, &size))
- return NULL;
-
- _channel.state = SI_STATE_FINISHED; /* Don't play both PCM and music */
-
- return makeStream(_data.begin() + offset + SCI0_PCM_DATA_OFFSET, size, rate);
-}
-
-SongIterator *Sci0SongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_BASE) {
- switch (msg._type) {
-
- case _SIMSG_BASEMSG_PRINT:
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "SCI0: dev=%d, active-chan=%d, size=%d, loops=%d",
- _deviceId, _numActiveChannels, _data.size(), _loops);
- break;
-
- case _SIMSG_BASEMSG_SET_LOOPS:
- _loops = msg._arg.i;
- break;
-
- case _SIMSG_BASEMSG_STOP: {
- songit_id_t sought_id = msg.ID;
-
- if (sought_id == ID)
- _channel.state = SI_STATE_FINISHED;
- break;
- }
-
- case _SIMSG_BASEMSG_SET_PLAYMASK: {
- int i;
- _deviceId = msg._arg.i;
-
- /* Set all but the rhytm channel mask bits */
- _channel.playmask &= ~(1 << MIDI_RHYTHM_CHANNEL);
-
- for (i = 0; i < MIDI_CHANNELS; i++)
- if (_data[2 + (i << 1)] & _deviceId
- && i != MIDI_RHYTHM_CHANNEL)
- _channel.playmask |= (1 << i);
- }
- break;
-
- case _SIMSG_BASEMSG_SET_RHYTHM:
- _channel.playmask &= ~(1 << MIDI_RHYTHM_CHANNEL);
- if (msg._arg.i)
- _channel.playmask |= (1 << MIDI_RHYTHM_CHANNEL);
- break;
-
- case _SIMSG_BASEMSG_SET_FADE: {
- fade_params_t *fp = (fade_params_t *) msg._arg.p;
- fade.action = fp->action;
- fade.final_volume = fp->final_volume;
- fade.ticks_per_step = fp->ticks_per_step;
- fade.step_size = fp->step_size;
- break;
- }
-
- default:
- return NULL;
- }
-
- return this;
- }
- return NULL;
-}
-
-int Sci0SongIterator::getTimepos() {
- return _channel.total_timepos;
-}
-
-Sci0SongIterator::Sci0SongIterator(byte *data, uint size, songit_id_t id)
- : BaseSongIterator(data, size, id) {
- channel_mask = 0xffff; // Allocate all channels by default
- _channel.state = SI_STATE_UNINITIALISED;
-
- for (int i = 0; i < MIDI_CHANNELS; i++)
- _polyphony[i] = data[1 + (i << 1)];
-
- init();
-}
-
-void Sci0SongIterator::init() {
- fade.action = FADE_ACTION_NONE;
- _resetflag = 0;
- _loops = 0;
- priority = 0;
-
- _ccc = 0; /* Reset cumulative cue counter */
- _numActiveChannels = 1;
- _channel.init(0, SCI0_MIDI_OFFSET, _data.size());
- _channel.resetSynthChannels();
-
- if (_data[0] == 2) /* Do we have an embedded PCM? */
- _channel.state = SI_STATE_PCM;
-}
-
-SongIterator *Sci0SongIterator::clone(int delta) {
- Sci0SongIterator *newit = new Sci0SongIterator(*this);
- return newit;
-}
-
-
-/***************************/
-/*-- SCI1 song iterators --*/
-/***************************/
-
-int Sci1SongIterator::initSample(const int offset) {
- Sci1Sample sample;
- int rate;
- int length;
- int begin;
- int end;
-
- CHECK_FOR_END_ABSOLUTE((uint)offset + 10);
- if (_data[offset + 1] != 0)
- warning("[iterator-1] In sample at offset 0x04x: Byte #1 is %02x instead of zero",
- _data[offset + 1]);
-
- rate = (int16)READ_LE_UINT16(_data.begin() + offset + 2);
- length = READ_LE_UINT16(_data.begin() + offset + 4);
- begin = (int16)READ_LE_UINT16(_data.begin() + offset + 6);
- end = (int16)READ_LE_UINT16(_data.begin() + offset + 8);
-
- CHECK_FOR_END_ABSOLUTE((uint)(offset + 10 + length));
-
- sample.delta = begin;
- sample.size = length;
- sample._data = _data.begin() + offset + 10;
-
-#ifdef DEBUG_VERBOSE
- fprintf(stderr, "[SAMPLE] %x/%x/%x/%x l=%x\n",
- offset + 10, begin, end, _data.size(), length);
-#endif
-
- sample.rate = rate;
-
- sample.announced = false;
-
- /* Insert into the sample list at the right spot, keeping it sorted by delta */
- Common::List<Sci1Sample>::iterator seeker = _samples.begin();
- while (seeker != _samples.end() && seeker->delta < begin)
- ++seeker;
- _samples.insert(seeker, sample);
-
- return 0; /* Everything's fine */
-}
-
-int Sci1SongIterator::initSong() {
- int last_time;
- uint offset = 0;
- _numChannels = 0;
- _samples.clear();
-// _deviceId = 0x0c;
-
- if (_data[offset] == 0xf0) {
- priority = _data[offset + 1];
-
- offset += 8;
- }
-
- while (_data[offset] != 0xff
- && _data[offset] != _deviceId) {
- offset++;
- CHECK_FOR_END_ABSOLUTE(offset + 1);
- while (_data[offset] != 0xff) {
- CHECK_FOR_END_ABSOLUTE(offset + 7);
- offset += 6;
- }
- offset++;
- }
-
- if (_data[offset] == 0xff) {
- warning("[iterator] Song does not support hardware 0x%02x", _deviceId);
- return 1;
- }
-
- offset++;
-
- while (_data[offset] != 0xff) { /* End of list? */
- uint track_offset;
- int end;
- offset += 2;
-
- CHECK_FOR_END_ABSOLUTE(offset + 4);
-
- track_offset = READ_LE_UINT16(_data.begin() + offset);
- end = READ_LE_UINT16(_data.begin() + offset + 2);
-
- CHECK_FOR_END_ABSOLUTE(track_offset - 1);
-
- if (_data[track_offset] == 0xfe) {
- if (initSample(track_offset))
- return 1; /* Error */
- } else {
- /* Regular MIDI channel */
- if (_numChannels >= MIDI_CHANNELS) {
- warning("[iterator] Song has more than %d channels, cutting them off",
- MIDI_CHANNELS);
- break; /* Scan for remaining samples */
- } else {
- int channel_nr = _data[track_offset] & 0xf;
- SongIteratorChannel &channel = _channels[_numChannels++];
-
- /*
- if (_data[track_offset] & 0xf0)
- printf("Channel %d has mapping bits %02x\n",
- channel_nr, _data[track_offset] & 0xf0);
- */
-
- // Add 2 to skip over header bytes */
- channel.init(channel_nr, track_offset + 2, track_offset + end);
- channel.resetSynthChannels();
-
- _polyphony[_numChannels - 1] = _data[channel.offset - 1] & 15;
-
- channel.playmask = ~0; /* Enable all */
- channel_mask |= (1 << channel_nr);
-
- CHECK_FOR_END_ABSOLUTE(offset + end);
- }
- }
- offset += 4;
- CHECK_FOR_END_ABSOLUTE(offset);
- }
-
- /* Now ensure that sample deltas are relative to the previous sample */
- last_time = 0;
- _numActiveChannels = _numChannels;
- _numLoopedChannels = 0;
-
- for (Common::List<Sci1Sample>::iterator seeker = _samples.begin();
- seeker != _samples.end(); ++seeker) {
- int prev_last_time = last_time;
- //printf("[iterator] Detected sample: %d Hz, %d bytes at time %d\n",
- // seeker->format.rate, seeker->size, seeker->delta);
- last_time = seeker->delta;
- seeker->delta -= prev_last_time;
- }
-
- return 0; /* Success */
-}
-
-int Sci1SongIterator::getSmallestDelta() const {
- int d = -1;
- for (int i = 0; i < _numChannels; i++)
- if (_channels[i].state == SI_STATE_COMMAND
- && (d == -1 || _channels[i].delay < d))
- d = _channels[i].delay;
-
- if (!_samples.empty() && _samples.begin()->delta < d)
- return _samples.begin()->delta;
- else
- return d;
-}
-
-void Sci1SongIterator::updateDelta(int delta) {
- if (!_samples.empty())
- _samples.begin()->delta -= delta;
-
- for (int i = 0; i < _numChannels; i++)
- if (_channels[i].state == SI_STATE_COMMAND)
- _channels[i].delay -= delta;
-}
-
-bool Sci1SongIterator::noDeltaTime() const {
- for (int i = 0; i < _numChannels; i++)
- if (_channels[i].state == SI_STATE_DELTA_TIME)
- return false;
- return true;
-}
-
-#define COMMAND_INDEX_NONE -1
-#define COMMAND_INDEX_PCM -2
-
-int Sci1SongIterator::getCommandIndex() const {
- /* Determine the channel # of the next active event, or -1 */
- int i;
- int base_delay = 0x7ffffff;
- int best_chan = COMMAND_INDEX_NONE;
-
- for (i = 0; i < _numChannels; i++)
- if ((_channels[i].state != SI_STATE_PENDING)
- && (_channels[i].state != SI_STATE_FINISHED)) {
-
- if ((_channels[i].state == SI_STATE_DELTA_TIME)
- && (_channels[i].delay == 0))
- return i;
- /* First, read all unknown delta times */
-
- if (_channels[i].delay < base_delay) {
- best_chan = i;
- base_delay = _channels[i].delay;
- }
- }
-
- if (!_samples.empty() && base_delay >= _samples.begin()->delta)
- return COMMAND_INDEX_PCM;
-
- return best_chan;
-}
-
-
-Audio::AudioStream *Sci1SongIterator::getAudioStream() {
- Common::List<Sci1Sample>::iterator sample = _samples.begin();
- if (sample != _samples.end() && sample->delta <= 0) {
- Audio::AudioStream *feed = makeStream(sample->_data, sample->size, sample->rate);
- _samples.erase(sample);
-
- return feed;
- } else
- return NULL;
-}
-
-int Sci1SongIterator::nextCommand(byte *buf, int *result) {
-
- if (!_initialised) {
- //printf("[iterator] DEBUG: Initialising for %d\n", _deviceId);
- _initialised = true;
- if (initSong())
- return SI_FINISHED;
- }
-
-
- if (_delayRemaining) {
- int delay = _delayRemaining;
- _delayRemaining = 0;
- return delay;
- }
-
- int retval = 0;
- do { /* All delays must be processed separately */
- int chan = getCommandIndex();
-
- if (chan == COMMAND_INDEX_NONE) {
- return SI_FINISHED;
- }
-
- if (chan == COMMAND_INDEX_PCM) {
-
- if (_samples.begin()->announced) {
- /* Already announced; let's discard it */
- Audio::AudioStream *feed = getAudioStream();
- delete feed;
- } else {
- int delay = _samples.begin()->delta;
-
- if (delay) {
- updateDelta(delay);
- return delay;
- }
- /* otherwise we're touching a PCM */
- _samples.begin()->announced = true;
- return SI_PCM;
- }
- } else { /* Not a PCM */
-
- retval = processMidi(buf, result,
- &(_channels[chan]),
- PARSE_FLAG_LOOPS_UNLIMITED);
-
- if (retval == SI_LOOP) {
- _numLoopedChannels++;
- _channels[chan].state = SI_STATE_PENDING;
- _channels[chan].delay = 0;
-
- if (_numLoopedChannels == _numActiveChannels) {
- int i;
-
- /* Everyone's ready: Let's loop */
- for (i = 0; i < _numChannels; i++)
- if (_channels[i].state == SI_STATE_PENDING)
- _channels[i].state = SI_STATE_DELTA_TIME;
-
- _numLoopedChannels = 0;
- return SI_LOOP;
- }
- } else if (retval == SI_FINISHED) {
-#ifdef DEBUG
- fprintf(stderr, "FINISHED some channel\n");
-#endif
- } else if (retval > 0) {
- int sd ;
- sd = getSmallestDelta();
-
- if (noDeltaTime() && sd) {
- /* No other channel is ready */
- updateDelta(sd);
-
- /* Only from here do we return delta times */
- return sd;
- }
- }
-
- } /* Not a PCM */
-
- } while (retval > 0);
-
- return retval;
-}
-
-SongIterator *Sci1SongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_BASE) { /* May extend this in the future */
- switch (msg._type) {
-
- case _SIMSG_BASEMSG_PRINT: {
- int playmask = 0;
- int i;
-
- for (i = 0; i < _numChannels; i++)
- playmask |= _channels[i].playmask;
-
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "SCI1: chan-nr=%d, playmask=%04x",
- _numChannels, playmask);
- }
- break;
-
- case _SIMSG_BASEMSG_STOP: {
- songit_id_t sought_id = msg.ID;
- int i;
-
- if (sought_id == ID) {
- ID = 0;
-
- for (i = 0; i < _numChannels; i++)
- _channels[i].state = SI_STATE_FINISHED;
- }
- break;
- }
-
- case _SIMSG_BASEMSG_SET_PLAYMASK:
- if (msg.ID == ID) {
- channel_mask = 0;
-
- _deviceId = msg._arg.i;
-
- if (_initialised) {
- int i;
- int toffset = -1;
-
- for (i = 0; i < _numChannels; i++)
- if (_channels[i].state != SI_STATE_FINISHED
- && _channels[i].total_timepos > toffset) {
- toffset = _channels[i].total_timepos
- + _channels[i].timepos_increment
- - _channels[i].delay;
- }
-
- /* Find an active channel so that we can
- ** get the correct time offset */
-
- initSong();
-
- toffset -= _delayRemaining;
- _delayRemaining = 0;
-
- if (toffset > 0)
- return new_fast_forward_iterator(this, toffset);
- } else {
- initSong();
- _initialised = true;
- }
-
- break;
-
- }
-
- case _SIMSG_BASEMSG_SET_LOOPS:
- if (msg.ID == ID)
- _loops = (msg._arg.i > 32767) ? 99 : 0;
- /* 99 is arbitrary, but we can't use '1' because of
- ** the way we're testing in the decoding section. */
- break;
-
- case _SIMSG_BASEMSG_SET_HOLD:
- _hold = msg._arg.i;
- break;
- case _SIMSG_BASEMSG_SET_RHYTHM:
- /* Ignore */
- break;
-
- case _SIMSG_BASEMSG_SET_FADE: {
- fade_params_t *fp = (fade_params_t *) msg._arg.p;
- fade.action = fp->action;
- fade.final_volume = fp->final_volume;
- fade.ticks_per_step = fp->ticks_per_step;
- fade.step_size = fp->step_size;
- break;
- }
-
- default:
- warning("Unsupported command %d to SCI1 iterator", msg._type);
- }
- return this;
- }
- return NULL;
-}
-
-Sci1SongIterator::Sci1SongIterator(byte *data, uint size, songit_id_t id)
- : BaseSongIterator(data, size, id) {
- channel_mask = 0; // Defer channel allocation
-
- for (int i = 0; i < MIDI_CHANNELS; i++)
- _polyphony[i] = 0; // Unknown
-
- init();
-}
-
-void Sci1SongIterator::init() {
- fade.action = FADE_ACTION_NONE;
- _resetflag = 0;
- _loops = 0;
- priority = 0;
-
- _ccc = 0;
- _deviceId = 0x00; // Default to Sound Blaster/AdLib for purposes of cue computation
- _numChannels = 0;
- _initialised = false;
- _delayRemaining = 0;
- _loops = 0;
- _hold = 0;
- memset(_polyphony, 0, sizeof(_polyphony));
-}
-
-Sci1SongIterator::~Sci1SongIterator() {
-}
-
-
-SongIterator *Sci1SongIterator::clone(int delta) {
- Sci1SongIterator *newit = new Sci1SongIterator(*this);
- newit->_delayRemaining = delta;
- return newit;
-}
-
-int Sci1SongIterator::getTimepos() {
- int max = 0;
- int i;
-
- for (i = 0; i < _numChannels; i++)
- if (_channels[i].total_timepos > max)
- max = _channels[i].total_timepos;
-
- return max;
-}
-
-/**
- * A song iterator with the purpose of sending notes-off channel commands.
- */
-class CleanupSongIterator : public SongIterator {
-public:
- CleanupSongIterator(uint channels) {
- channel_mask = channels;
- ID = 17;
- }
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream() { return NULL; }
- SongIterator *handleMessage(Message msg);
- int getTimepos() { return 0; }
- SongIterator *clone(int delta) { return new CleanupSongIterator(*this); }
-};
-
-SongIterator *CleanupSongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_BASEMSG_PRINT && msg._type == _SIMSG_BASEMSG_PRINT) {
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "CLEANUP");
- }
-
- return NULL;
-}
-
-int CleanupSongIterator::nextCommand(byte *buf, int *result) {
- /* Task: Return channel-notes-off for each channel */
- if (channel_mask) {
- int bs = sci_ffs(channel_mask) - 1;
-
- channel_mask &= ~(1 << bs);
- buf[0] = 0xb0 | bs; /* Controller */
- buf[1] = SCI_MIDI_CHANNEL_NOTES_OFF;
- buf[2] = 0; /* Hmm... */
- *result = 3;
- return 0;
- } else
- return SI_FINISHED;
-}
-
-/**********************/
-/*-- Timer iterator --*/
-/**********************/
-int TimerSongIterator::nextCommand(byte *buf, int *result) {
- if (_delta) {
- int d = _delta;
- _delta = 0;
- return d;
- }
- return SI_FINISHED;
-}
-
-SongIterator *new_timer_iterator(int delta) {
- return new TimerSongIterator(delta);
-}
-
-/**********************************/
-/*-- Fast-forward song iterator --*/
-/**********************************/
-
-int FastForwardSongIterator::nextCommand(byte *buf, int *result) {
- if (_delta <= 0)
- return SI_MORPH; /* Did our duty */
-
- while (1) {
- int rv = _delegate->nextCommand(buf, result);
-
- if (rv > 0) {
- /* Subtract from the delta we want to wait */
- _delta -= rv;
-
- /* Done */
- if (_delta < 0)
- return -_delta;
- }
-
- if (rv <= 0)
- return rv;
- }
-}
-
-Audio::AudioStream *FastForwardSongIterator::getAudioStream() {
- return _delegate->getAudioStream();
-}
-
-SongIterator *FastForwardSongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_PLASTICWRAP) {
- assert(msg._type == _SIMSG_PLASTICWRAP_ACK_MORPH);
-
- if (_delta <= 0) {
- SongIterator *it = _delegate;
- delete this;
- return it;
- }
-
- warning("[ff-iterator] Morphing without need");
- return this;
- }
-
- if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) {
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "FASTFORWARD:");
- msg._arg.i++;
- }
-
- // And continue with the delegate
- songit_handle_message(&_delegate, msg);
-
- return NULL;
-}
-
-
-int FastForwardSongIterator::getTimepos() {
- return _delegate->getTimepos();
-}
-
-FastForwardSongIterator::FastForwardSongIterator(SongIterator *capsit, int delta)
- : _delegate(capsit), _delta(delta) {
-
- channel_mask = capsit->channel_mask;
-}
-
-SongIterator *FastForwardSongIterator::clone(int delta) {
- FastForwardSongIterator *newit = new FastForwardSongIterator(*this);
- newit->_delegate = _delegate->clone(delta);
- return newit;
-}
-
-SongIterator *new_fast_forward_iterator(SongIterator *capsit, int delta) {
- if (capsit == NULL)
- return NULL;
-
- FastForwardSongIterator *it = new FastForwardSongIterator(capsit, delta);
- return it;
-}
-
-
-/********************/
-/*-- Tee iterator --*/
-/********************/
-
-
-static void song_iterator_add_death_listener(SongIterator *it, TeeSongIterator *client) {
- for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) {
- if (it->_deathListeners[i] == 0) {
- it->_deathListeners[i] = client;
- return;
- }
- }
- error("FATAL: Too many death listeners for song iterator");
-}
-
-static void song_iterator_remove_death_listener(SongIterator *it, TeeSongIterator *client) {
- for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) {
- if (it->_deathListeners[i] == client) {
- it->_deathListeners[i] = 0;
- return;
- }
- }
-}
-
-static void song_iterator_transfer_death_listeners(SongIterator *it, SongIterator *it_from) {
- for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i) {
- if (it_from->_deathListeners[i])
- song_iterator_add_death_listener(it, it_from->_deathListeners[i]);
- it_from->_deathListeners[i] = 0;
- }
-}
-
-static void songit_tee_death_notification(TeeSongIterator *self, SongIterator *corpse) {
- if (corpse == self->_children[TEE_LEFT].it) {
- self->_status &= ~TEE_LEFT_ACTIVE;
- self->_children[TEE_LEFT].it = NULL;
- } else if (corpse == self->_children[TEE_RIGHT].it) {
- self->_status &= ~TEE_RIGHT_ACTIVE;
- self->_children[TEE_RIGHT].it = NULL;
- } else {
- error("songit_tee_death_notification() failed: Breakpoint in %s, line %d", __FILE__, __LINE__);
- }
-}
-
-TeeSongIterator::TeeSongIterator(SongIterator *left, SongIterator *right) {
- int i;
- int firstfree = 1; /* First free channel */
- int incomplete_map = 0;
-
- _readyToMorph = false;
- _status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE;
-
- _children[TEE_LEFT].it = left;
- _children[TEE_RIGHT].it = right;
-
- /* Default to lhs channels */
- channel_mask = left->channel_mask;
- for (i = 0; i < 16; i++)
- if (channel_mask & (1 << i) & right->channel_mask
- && (i != MIDI_RHYTHM_CHANNEL) /* Share rhythm */) { /*conflict*/
- while ((firstfree == MIDI_RHYTHM_CHANNEL)
- /* Either if it's the rhythm channel or if it's taken */
- || (firstfree < MIDI_CHANNELS
- && ((1 << firstfree) & channel_mask)))
- ++firstfree;
-
- if (firstfree == MIDI_CHANNELS) {
- incomplete_map = 1;
- //warning("[songit-tee <%08lx,%08lx>] Could not remap right channel #%d: Out of channels",
- // left->ID, right->ID, i);
- } else {
- _children[TEE_RIGHT].it->channel_remap[i] = firstfree;
-
- channel_mask |= (1 << firstfree);
- }
- }
-#ifdef DEBUG_TEE_ITERATOR
- if (incomplete_map) {
- int c;
- fprintf(stderr, "[songit-tee <%08lx,%08lx>] Channels:"
- " %04x <- %04x | %04x\n",
- left->ID, right->ID,
- channel_mask,
- left->channel_mask, right->channel_mask);
- for (c = 0 ; c < 2; c++)
- for (i = 0 ; i < 16; i++)
- fprintf(stderr, " map [%d][%d] -> %d\n",
- c, i, _children[c].it->channel_remap[i]);
- }
-#endif
-
-
- song_iterator_add_death_listener(left, this);
- song_iterator_add_death_listener(right, this);
-}
-
-TeeSongIterator::~TeeSongIterator() {
- // When we die, remove any listeners from our children
- if (_children[TEE_LEFT].it) {
- song_iterator_remove_death_listener(_children[TEE_LEFT].it, this);
- }
-
- if (_children[TEE_RIGHT].it) {
- song_iterator_remove_death_listener(_children[TEE_RIGHT].it, this);
- }
-}
-
-
-int TeeSongIterator::nextCommand(byte *buf, int *result) {
- static const int ready_masks[2] = {TEE_LEFT_READY, TEE_RIGHT_READY};
- static const int active_masks[2] = {TEE_LEFT_ACTIVE, TEE_RIGHT_ACTIVE};
- static const int pcm_masks[2] = {TEE_LEFT_PCM, TEE_RIGHT_PCM};
- int i;
- int retid;
-
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "[Tee] %02x\n", _status);
-#endif
-
- if (!(_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE)))
- /* None is active? */
- return SI_FINISHED;
-
- if (_readyToMorph)
- return SI_MORPH;
-
- if ((_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE))
- != (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE)) {
- /* Not all are is active? */
- int which = 0;
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "\tRequesting transformation...\n");
-#endif
- if (_status & TEE_LEFT_ACTIVE)
- which = TEE_LEFT;
- else if (_status & TEE_RIGHT_ACTIVE)
- which = TEE_RIGHT;
- memcpy(buf, _children[which].buf, sizeof(buf));
- *result = _children[which].result;
- _readyToMorph = true;
- return _children[which].retval;
- }
-
- /* First, check for unreported PCMs */
- for (i = TEE_LEFT; i <= TEE_RIGHT; i++)
- if ((_status & (ready_masks[i] | pcm_masks[i]))
- == (ready_masks[i] | pcm_masks[i])) {
- _status &= ~ready_masks[i];
- return SI_PCM;
- }
-
- for (i = TEE_LEFT; i <= TEE_RIGHT; i++)
- if (!(_status & ready_masks[i])) {
-
- /* Buffers aren't ready yet */
- _children[i].retval =
- songit_next(&(_children[i].it),
- _children[i].buf,
- &(_children[i].result),
- IT_READER_MASK_ALL
- | IT_READER_MAY_FREE
- | IT_READER_MAY_CLEAN);
-
- _status |= ready_masks[i];
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "\t Must check %d: %d\n", i, _children[i].retval);
-#endif
-
- if (_children[i].retval == SI_ABSOLUTE_CUE ||
- _children[i].retval == SI_RELATIVE_CUE)
- return _children[i].retval;
- if (_children[i].retval == SI_FINISHED) {
- _status &= ~active_masks[i];
- /* Recurse to complete */
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "\t Child %d signalled completion, recursing w/ status %02x\n", i, _status);
-#endif
- return nextCommand(buf, result);
- } else if (_children[i].retval == SI_PCM) {
- _status |= pcm_masks[i];
- _status &= ~ready_masks[i];
- return SI_PCM;
- }
- }
-
-
- /* We've already handled PCM, MORPH and FINISHED, CUEs & LOOP remain */
-
- retid = TEE_LEFT;
- if ((_children[TEE_LEFT].retval > 0)
- /* Asked to delay */
- && (_children[TEE_RIGHT].retval <= _children[TEE_LEFT].retval))
- /* Is not delaying or not delaying as much */
- retid = TEE_RIGHT;
-
-#ifdef DEBUG_TEE_ITERATOR
- fprintf(stderr, "\tl:%d / r:%d / chose %d\n",
- _children[TEE_LEFT].retval, _children[TEE_RIGHT].retval, retid);
-#endif
-
- /* Adjust delta times */
- if (_children[retid].retval > 0
- && _children[1-retid].retval > 0) {
- if (_children[1-retid].retval
- == _children[retid].retval)
- /* If both _children wait the same amount of time,
- ** we have to re-fetch commands from both */
- _status &= ~ready_masks[1-retid];
- else
- /* If they don't, we can/must re-use the other
- ** child's delay time */
- _children[1-retid].retval
- -= _children[retid].retval;
- }
-
- _status &= ~ready_masks[retid];
- memcpy(buf, _children[retid].buf, sizeof(buf));
- *result = _children[retid].result;
-
- return _children[retid].retval;
-}
-
-Audio::AudioStream *TeeSongIterator::getAudioStream() {
- static const int pcm_masks[2] = {TEE_LEFT_PCM, TEE_RIGHT_PCM};
- int i;
-
- for (i = TEE_LEFT; i <= TEE_RIGHT; i++)
- if (_status & pcm_masks[i]) {
- _status &= ~pcm_masks[i];
- return _children[i].it->getAudioStream();
- }
-
- return NULL; // No iterator
-}
-
-SongIterator *TeeSongIterator::handleMessage(Message msg) {
- if (msg._class == _SIMSG_PLASTICWRAP) {
- assert(msg._type == _SIMSG_PLASTICWRAP_ACK_MORPH);
-
- SongIterator *old_it;
- if (!(_status & (TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE))) {
- delete this;
- return NULL;
- } else if (!(_status & TEE_LEFT_ACTIVE)) {
- delete _children[TEE_LEFT].it;
- _children[TEE_LEFT].it = 0;
- old_it = _children[TEE_RIGHT].it;
- song_iterator_remove_death_listener(old_it, this);
- song_iterator_transfer_death_listeners(old_it, this);
- delete this;
- return old_it;
- } else if (!(_status & TEE_RIGHT_ACTIVE)) {
- delete _children[TEE_RIGHT].it;
- _children[TEE_RIGHT].it = 0;
- old_it = _children[TEE_LEFT].it;
- song_iterator_remove_death_listener(old_it, this);
- song_iterator_transfer_death_listeners(old_it, this);
- delete this;
- return old_it;
- }
-
- warning("[tee-iterator] Morphing without need");
- return this;
- }
-
- if (msg._class == _SIMSG_BASE && msg._type == _SIMSG_BASEMSG_PRINT) {
- print_tabs_id(msg._arg.i, ID);
- debugC(2, kDebugLevelSound, "TEE:");
- msg._arg.i++;
- }
-
- // And continue with the children
- if (_children[TEE_LEFT].it)
- songit_handle_message(&(_children[TEE_LEFT].it), msg);
- if (_children[TEE_RIGHT].it)
- songit_handle_message(&(_children[TEE_RIGHT].it), msg);
-
- return NULL;
-}
-
-void TeeSongIterator::init() {
- _status = TEE_LEFT_ACTIVE | TEE_RIGHT_ACTIVE;
- _children[TEE_LEFT].it->init();
- _children[TEE_RIGHT].it->init();
-}
-
-SongIterator *TeeSongIterator::clone(int delta) {
- TeeSongIterator *newit = new TeeSongIterator(*this);
-
- if (_children[TEE_LEFT].it)
- newit->_children[TEE_LEFT].it = _children[TEE_LEFT].it->clone(delta);
- if (_children[TEE_RIGHT].it)
- newit->_children[TEE_RIGHT].it = _children[TEE_RIGHT].it->clone(delta);
-
- return newit;
-}
-
-
-/*************************************/
-/*-- General purpose functionality --*/
-/*************************************/
-
-int songit_next(SongIterator **it, byte *buf, int *result, int mask) {
- int retval;
-
- if (!*it)
- return SI_FINISHED;
-
- do {
- retval = (*it)->nextCommand(buf, result);
- if (retval == SI_MORPH) {
- debugC(2, kDebugLevelSound, " Morphing %p (stored at %p)", (void *)*it, (void *)it);
- if (!SIMSG_SEND((*it), SIMSG_ACK_MORPH)) {
- error("SI_MORPH failed. Breakpoint in %s, line %d", __FILE__, __LINE__);
- } else
- debugC(2, kDebugLevelSound, "SI_MORPH successful");
- }
-
- if (retval == SI_FINISHED)
- debugC(2, kDebugLevelSound, "[song-iterator] Song finished. mask = %04x, cm=%04x",
- mask, (*it)->channel_mask);
- if (retval == SI_FINISHED
- && (mask & IT_READER_MAY_CLEAN)
- && (*it)->channel_mask) { /* This last test will fail
- ** with a terminated
- ** cleanup iterator */
- int channel_mask = (*it)->channel_mask;
-
- SongIterator *old_it = *it;
- *it = new CleanupSongIterator(channel_mask);
- for(uint i = 0; i < MIDI_CHANNELS; i++)
- (*it)->channel_remap[i] = old_it->channel_remap[i];
- song_iterator_transfer_death_listeners(*it, old_it);
- if (mask & IT_READER_MAY_FREE)
- delete old_it;
- retval = -9999; /* Continue */
- }
- } while (!( /* Until one of the following holds */
- (retval > 0 && (mask & IT_READER_MASK_DELAY))
- || (retval == 0 && (mask & IT_READER_MASK_MIDI))
- || (retval == SI_LOOP && (mask & IT_READER_MASK_LOOP))
- || (retval == SI_ABSOLUTE_CUE &&
- (mask & IT_READER_MASK_CUE))
- || (retval == SI_RELATIVE_CUE &&
- (mask & IT_READER_MASK_CUE))
- || (retval == SI_PCM && (mask & IT_READER_MASK_PCM))
- || (retval == SI_FINISHED)
- ));
-
- if (retval == SI_FINISHED && (mask & IT_READER_MAY_FREE)) {
- delete *it;
- *it = NULL;
- }
-
- return retval;
-}
-
-SongIterator::SongIterator() {
- ID = 0;
- channel_mask = 0;
- fade.action = FADE_ACTION_NONE;
- priority = 0;
- memset(_deathListeners, 0, sizeof(_deathListeners));
-
- // By default, don't remap
- for (uint i = 0; i < 16; i++)
- channel_remap[i] = i;
-}
-
-SongIterator::SongIterator(const SongIterator &si) {
- ID = si.ID;
- channel_mask = si.channel_mask;
- fade = si.fade;
- priority = si.priority;
- memset(_deathListeners, 0, sizeof(_deathListeners));
-
- for (uint i = 0; i < 16; i++)
- channel_remap[i] = si.channel_remap[i];
-}
-
-
-SongIterator::~SongIterator() {
- for (int i = 0; i < SONGIT_MAX_LISTENERS; ++i)
- if (_deathListeners[i])
- songit_tee_death_notification(_deathListeners[i], this);
-}
-
-SongIterator *songit_new(byte *data, uint size, SongIteratorType type, songit_id_t id) {
- BaseSongIterator *it;
-
- if (!data || size < 22) {
- warning("Attempt to instantiate song iterator for null song data");
- return NULL;
- }
-
-
- switch (type) {
- case SCI_SONG_ITERATOR_TYPE_SCI0:
- it = new Sci0SongIterator(data, size, id);
- break;
-
- case SCI_SONG_ITERATOR_TYPE_SCI1:
- it = new Sci1SongIterator(data, size, id);
- break;
-
- default:
- /**-- Invalid/unsupported sound resources --**/
- warning("Attempt to instantiate invalid/unknown song iterator type %d", type);
- return NULL;
- }
-
- return it;
-}
-
-int songit_handle_message(SongIterator **it_reg_p, SongIterator::Message msg) {
- SongIterator *it = *it_reg_p;
- SongIterator *newit;
-
- newit = it->handleMessage(msg);
-
- if (!newit)
- return 0; /* Couldn't handle */
-
- *it_reg_p = newit; /* Might have self-morphed */
- return 1;
-}
-
-SongIterator *sfx_iterator_combine(SongIterator *it1, SongIterator *it2) {
- if (it1 == NULL)
- return it2;
- if (it2 == NULL)
- return it1;
-
- /* Both are non-NULL: */
- return new TeeSongIterator(it1, it2);
-}
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
diff --git a/engines/sci/sound/iterator/iterator.h b/engines/sci/sound/iterator/iterator.h
deleted file mode 100644
index e5c8f50702..0000000000
--- a/engines/sci/sound/iterator/iterator.h
+++ /dev/null
@@ -1,326 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/* Song iterator declarations */
-
-#ifndef SCI_SFX_SFX_ITERATOR_H
-#define SCI_SFX_SFX_ITERATOR_H
-
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#include "sci/sound/drivers/mididriver.h"
-
-namespace Audio {
- class AudioStream;
-}
-
-namespace Sci {
-
-enum SongIteratorStatus {
- SI_FINISHED = -1, /**< Song finished playing */
- SI_LOOP = -2, /**< Song just looped */
- SI_ABSOLUTE_CUE = -3, /**< Found a song cue (absolute) */
- SI_RELATIVE_CUE = -4, /**< Found a song cue (relative) */
- SI_PCM = -5, /**< Found a PCM */
- SI_IGNORE = -6, /**< This event got edited out by the remapper */
- SI_MORPH = -255 /**< Song iterator requested self-morph. */
-};
-
-#define FADE_ACTION_NONE 0
-#define FADE_ACTION_FADE_AND_STOP 1
-#define FADE_ACTION_FADE_AND_CONT 2
-
-struct fade_params_t {
- int ticks_per_step;
- int final_volume;
- int step_size;
- int action;
-};
-
-/* Helper defs for messages */
-enum {
- _SIMSG_BASE, /* Any base decoder */
- _SIMSG_PLASTICWRAP /* Any "Plastic" (discardable) wrapper decoder */
-};
-
-/* Base messages */
-enum {
- _SIMSG_BASEMSG_SET_LOOPS, /* Set loops */
- _SIMSG_BASEMSG_SET_PLAYMASK, /* Set the current playmask for filtering */
- _SIMSG_BASEMSG_SET_RHYTHM, /* Activate/deactivate rhythm channel */
- _SIMSG_BASEMSG_ACK_MORPH, /* Acknowledge self-morph */
- _SIMSG_BASEMSG_STOP, /* Stop iterator */
- _SIMSG_BASEMSG_PRINT, /* Print self to stderr, after printing param1 tabs */
- _SIMSG_BASEMSG_SET_HOLD, /* Set value of hold parameter to expect */
- _SIMSG_BASEMSG_SET_FADE /* Set fade parameters */
-};
-
-/* "Plastic" (discardable) wrapper messages */
-enum {
- _SIMSG_PLASTICWRAP_ACK_MORPH = _SIMSG_BASEMSG_ACK_MORPH /* Acknowledge self-morph */
-};
-
-/* Messages */
-#define SIMSG_SET_LOOPS(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_LOOPS,(x)
-#define SIMSG_SET_PLAYMASK(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_PLAYMASK,(x)
-#define SIMSG_SET_RHYTHM(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_RHYTHM,(x)
-#define SIMSG_ACK_MORPH _SIMSG_PLASTICWRAP,_SIMSG_PLASTICWRAP_ACK_MORPH,0
-#define SIMSG_STOP _SIMSG_BASE,_SIMSG_BASEMSG_STOP,0
-#define SIMSG_PRINT(indentation) _SIMSG_BASE,_SIMSG_BASEMSG_PRINT,(indentation)
-#define SIMSG_SET_HOLD(x) _SIMSG_BASE,_SIMSG_BASEMSG_SET_HOLD,(x)
-
-/* Message transmission macro: Takes song reference, message reference */
-#define SIMSG_SEND(o, m) songit_handle_message(&(o), SongIterator::Message((o)->ID, m))
-#define SIMSG_SEND_FADE(o, m) songit_handle_message(&(o), SongIterator::Message((o)->ID, _SIMSG_BASE, _SIMSG_BASEMSG_SET_FADE, m))
-
-typedef unsigned long songit_id_t;
-
-
-#define SONGIT_MAX_LISTENERS 2
-
-class TeeSongIterator;
-
-class SongIterator {
-public:
- struct Message {
- songit_id_t ID;
- uint _class; /* Type of iterator supposed to receive this */
- uint _type;
- union {
- uint i;
- void *p;
- } _arg;
-
- Message() : ID(0), _class(0xFFFF), _type(0xFFFF) {}
-
- /**
- * Create a song iterator message.
- *
- * @param id: song ID the message is targeted to
- * @param recipient_class: Message recipient class
- * @param type message type
- * @param a argument
- *
- * @note You should only use this with the SIMSG_* macros
- */
- Message(songit_id_t id, int recipient_class, int type, int a)
- : ID(id), _class(recipient_class), _type(type) {
- _arg.i = a;
- }
-
- /**
- * Create a song iterator message, wherein the first parameter is a pointer.
- *
- * @param id: song ID the message is targeted to
- * @param recipient_class: Message recipient class
- * @param type message type
- * @param a argument
- *
- * @note You should only use this with the SIMSG_* macros
- */
- Message(songit_id_t id, int recipient_class, int type, void *a)
- : ID(id), _class(recipient_class), _type(type) {
- _arg.p = a;
- }
- };
-
-public:
- songit_id_t ID;
- uint16 channel_mask; /* Bitmask of all channels this iterator will use */
- fade_params_t fade;
- int priority;
-
- /* Death listeners */
- /* These are not reset during initialisation */
- TeeSongIterator *_deathListeners[SONGIT_MAX_LISTENERS];
-
- /* See songit_* for the constructor and non-virtual member functions */
-
- byte channel_remap[MIDI_CHANNELS]; ///< Remapping for channels
-
-public:
- SongIterator();
- SongIterator(const SongIterator &);
- virtual ~SongIterator();
-
- /**
- * Resets/initializes the sound iterator.
- */
- virtual void init() {}
-
- /**
- * Reads the next MIDI operation _or_ delta time.
- * @param buf The buffer to write to (needs to be able to store at least 4 bytes)
- * @param result Number of bytes written to the buffer
- * (equals the number of bytes that need to be passed
- * to the lower layers) for 0, the cue value for SI_CUE,
- * or the number of loops remaining for SI_LOOP.
- * @return zero if a MIDI operation was written, SI_FINISHED
- * if the song has finished playing, SI_LOOP if looping
- * (after updating the loop variable), SI_CUE if we found
- * a cue, SI_PCM if a PCM was found, or the number of ticks
- * to wait before this function should be called next.
- *
- * @note If SI_PCM is returned, get_pcm() may be used to retrieve the associated
- * PCM, but this must be done before any subsequent calls to next().
- *
- * @todo The actual buffer size should either be specified or passed in, so that
- * we can detect buffer overruns.
- */
- virtual int nextCommand(byte *buf, int *result) = 0;
-
- /**
- Checks for the presence of a pcm sample.
- * @return NULL if no PCM data was found, an AudioStream otherwise.
- */
- virtual Audio::AudioStream *getAudioStream() = 0;
-
- /**
- * Handles a message to the song iterator.
- * @param msg the message to handle
- * @return NULL if the message was not understood,
- * this if the message could be handled, or a new song iterator
- * if the current iterator had to be morphed (but the message could
- * still be handled)
- *
- * @note This function is not supposed to be called directly; use
- * songit_handle_message() instead. It should not recurse, since songit_handle_message()
- * takes care of that and makes sure that its delegate received the message (and
- * was morphed) before self.
- */
- virtual SongIterator *handleMessage(Message msg) = 0;
-
- /**
- * Gets the song position to store in a savegame.
- */
- virtual int getTimepos() = 0;
-
- /**
- * Clone this song iterator.
- * @param delta number of ticks that still need to elapse until the
- * next item should be read from the song iterator
- */
- virtual SongIterator *clone(int delta) = 0;
-
-
-private:
- // Make the assignment operator unreachable, just in case...
- SongIterator& operator=(const SongIterator&);
-};
-
-
-/********************************/
-/*-- Song iterator operations --*/
-/********************************/
-
-enum SongIteratorType {
- SCI_SONG_ITERATOR_TYPE_SCI0 = 0,
- SCI_SONG_ITERATOR_TYPE_SCI1 = 1
-};
-
-#define IT_READER_MASK_MIDI (1 << 0)
-#define IT_READER_MASK_DELAY (1 << 1)
-#define IT_READER_MASK_LOOP (1 << 2)
-#define IT_READER_MASK_CUE (1 << 3)
-#define IT_READER_MASK_PCM (1 << 4)
-#define IT_READER_MAY_FREE (1 << 10) /* Free SI_FINISHED iterators */
-#define IT_READER_MAY_CLEAN (1 << 11)
-/* MAY_CLEAN: May instantiate cleanup iterators
-** (use for players; this closes open channels at the end of a song) */
-
-#define IT_READER_MASK_ALL ( IT_READER_MASK_MIDI \
- | IT_READER_MASK_DELAY \
- | IT_READER_MASK_LOOP \
- | IT_READER_MASK_CUE \
- | IT_READER_MASK_PCM )
-
-/* Convenience wrapper around it->next
-** Parameters: (SongIterator **it) Reference to the iterator to access
-** (byte *) buf: The buffer to write to (needs to be able to
-** store at least 4 bytes)
-** (int) mask: IT_READER_MASK options specifying the events to
-** listen for
-** Returns : (int) zero if a MIDI operation was written, SI_FINISHED
-** if the song has finished playing, SI_LOOP if looping
-** (after updating the loop variable), SI_CUE if we found
-** a cue, SI_PCM if a PCM was found, or the number of ticks
-** to wait before this function should be called next.
-** (int) *result: Number of bytes written to the buffer
-** (equals the number of bytes that need to be passed
-** to the lower layers) for 0, the cue value for SI_CUE,
-** or the number of loops remaining for SI_LOOP.
-*/
-int songit_next(SongIterator **it, byte *buf, int *result, int mask);
-
-/* Constructs a new song iterator object
-** Parameters: (byte *) data: The song data to iterate over
-** (uint) size: Number of bytes in the song
-** (int) type: One of the SCI_SONG_ITERATOR_TYPEs
-** (songit_id_t) id: An ID for addressing the song iterator
-** Returns : (SongIterator *) A newly allocated but uninitialized song
-** iterator, or NULL if 'type' was invalid or unsupported
-*/
-SongIterator *songit_new(byte *data, uint size, SongIteratorType type, songit_id_t id);
-
-/* Constructs a new song timer iterator object
-** Parameters: (int) delta: The delta after which to fire SI_FINISHED
-** Returns : (SongIterator *) A newly allocated but uninitialized song
-** iterator
-*/
-SongIterator *new_timer_iterator(int delta);
-
-/* Handles a message to the song iterator
-** Parameters: (SongIterator **): A reference to the variable storing the song iterator
-** Returns : (int) Non-zero if the message was understood
-** The song iterator may polymorph as result of msg, so a writeable reference is required.
-*/
-int songit_handle_message(SongIterator **it_reg, SongIterator::Message msg);
-
-
-/* Creates a new song iterator which fast-forwards
-** Parameters: (SongIterator *) it: The iterator to wrap
-** (int) delta: The number of ticks to skip
-** Returns : (SongIterator) A newly created song iterator
-** which skips all delta times
-** until 'delta' has been used up
-*/
-SongIterator *new_fast_forward_iterator(SongIterator *it, int delta);
-
-/* Combines two song iterators into one
-** Parameters: (sfx_iterator_t *) it1: One of the two iterators, or NULL
-** (sfx_iterator_t *) it2: The other iterator, or NULL
-** Returns : (sfx_iterator_t *) A combined iterator
-** If a combined iterator is returned, it will be flagged to be allowed to
-** dispose of 'it1' and 'it2', where applicable. This means that this
-** call should be used by song players, but not by the core sound system
-*/
-SongIterator *sfx_iterator_combine(SongIterator *it1, SongIterator *it2);
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
-
-#endif // SCI_SFX_SFX_ITERATOR_H
diff --git a/engines/sci/sound/iterator/iterator_internal.h b/engines/sci/sound/iterator/iterator_internal.h
deleted file mode 100644
index 5a0f0d3ec9..0000000000
--- a/engines/sci/sound/iterator/iterator_internal.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef SCI_SFX_SFX_ITERATOR_INTERNAL
-#define SCI_SFX_SFX_ITERATOR_INTERNAL
-
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#include "sci/sound/iterator/iterator.h"
-#include "sci/sound/drivers/mididriver.h"
-
-#include "common/array.h"
-#include "common/list.h"
-
-namespace Sci {
-
-/* Iterator types */
-
-enum {
- SI_STATE_UNINITIALISED = -1,
- SI_STATE_DELTA_TIME = 0, ///< Now at a delta time
- SI_STATE_COMMAND = 1, ///< Now at a MIDI operation
- SI_STATE_PENDING = 2, ///< Pending for loop
- SI_STATE_FINISHED = 3, ///< End of song
- SI_STATE_PCM = 4, ///< Should report a PCM next (-> DELTA_TIME)
- SI_STATE_PCM_MAGIC_DELTA = 5 ///< Should report a ``magic'' one tick delta time next (goes on to FINISHED)
-};
-
-struct SongIteratorChannel {
-
- int state; ///< State of this song iterator channel
- int offset; ///< Offset into the data chunk */
- int end; ///< Last allowed byte in track */
- int id; ///< Some channel ID */
-
- /**
- * Number of ticks before the specified channel is next used, or
- * CHANNEL_DELAY_MISSING to indicate that the delay has not yet
- * been read.
- */
- int delay;
-
- /* Two additional offsets for recovering: */
- int loop_offset;
- int initial_offset;
-
- int playmask; ///< Active playmask (MIDI channels to play in here) */
- int loop_timepos; ///< Total delay for this channel's loop marker */
- int total_timepos; ///< Number of ticks since the beginning, ignoring loops */
- int timepos_increment; ///< Number of ticks until the next command (to add) */
-
- byte last_cmd; ///< Last operation executed, for running status */
-
-public:
- void init(int id, int offset, int end);
- void resetSynthChannels();
-};
-
-class BaseSongIterator : public SongIterator {
-public:
- int _polyphony[MIDI_CHANNELS]; ///< # of simultaneous notes on each
-
- int _ccc; ///< Cumulative cue counter, for those who need it
- byte _resetflag; ///< for 0x4C -- on DoSound StopSound, do we return to start?
- int _deviceId; ///< ID of the device we generating events for
- int _numActiveChannels; ///< Number of active channels
- Common::Array<byte> _data; ///< Song data
-
- int _loops; ///< Number of loops remaining
-
-public:
- BaseSongIterator(byte *data, uint size, songit_id_t id);
-
-protected:
- int parseMidiCommand(byte *buf, int *result, SongIteratorChannel *channel, int flags);
- int processMidi(byte *buf, int *result, SongIteratorChannel *channel, int flags);
-};
-
-/********************************/
-/*--------- SCI 0 --------------*/
-/********************************/
-
-class Sci0SongIterator : public BaseSongIterator {
-public:
- SongIteratorChannel _channel;
-
-public:
- Sci0SongIterator(byte *data, uint size, songit_id_t id);
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream();
- SongIterator *handleMessage(Message msg);
- void init();
- int getTimepos();
- SongIterator *clone(int delta);
-};
-
-
-/********************************/
-/*--------- SCI 1 --------------*/
-/********************************/
-
-
-struct Sci1Sample {
- /**
- * Time left-- initially, this is 'Sample point 1'.
- * After initialisation, it is 'sample point 1 minus the sample
- * point of the previous sample'
- */
- int delta;
- int size;
- bool announced; /* Announced for download (SI_PCM) */
- int rate;
- byte *_data;
-};
-
-class Sci1SongIterator : public BaseSongIterator {
-public:
- SongIteratorChannel _channels[MIDI_CHANNELS];
-
- /* Invariant: Whenever channels[i].delay == CHANNEL_DELAY_MISSING,
- ** channel_offset[i] points to a delta time object. */
-
- bool _initialised; /**!< Whether the MIDI channel setup has been initialised */
- int _numChannels; /**!< Number of channels actually used */
- Common::List<Sci1Sample> _samples;
- int _numLoopedChannels; /**!< Number of channels that are ready to loop */
-
- int _delayRemaining; /**!< Number of ticks that haven't been polled yet */
- int _hold;
-
-public:
- Sci1SongIterator(byte *data, uint size, songit_id_t id);
- ~Sci1SongIterator();
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream();
- SongIterator *handleMessage(Message msg);
- void init();
- int getTimepos();
- SongIterator *clone(int delta);
-
-private:
- int initSample(const int offset);
- int initSong();
-
- int getSmallestDelta() const;
-
- void updateDelta(int delta);
-
- /** Checks that none of the channels is waiting for its delta to be read */
- bool noDeltaTime() const;
-
- /** Determine the channel # of the next active event, or -1 */
- int getCommandIndex() const;
-};
-
-#define PLAYMASK_NONE 0x0
-
-/***************************/
-/*--------- Timer ---------*/
-/***************************/
-
-/**
- * A song iterator which waits a specified time and then fires
- * SI_FINISHED. Used by DoSound, where audio resources are played (SCI1)
- */
-class TimerSongIterator : public SongIterator {
-protected:
- int _delta; /**!< Remaining time */
-
-public:
- TimerSongIterator(int delta) : _delta(delta) {}
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream() { return NULL; }
- SongIterator *handleMessage(Message msg) { return NULL; }
- int getTimepos() { return 0; }
- SongIterator *clone(int delta) { return new TimerSongIterator(*this); }
-};
-
-/**********************************/
-/*--------- Fast Forward ---------*/
-/**********************************/
-
-/**
- * A song iterator which fast-forwards another iterator.
- * Skips all delta times until a specified 'delta' has been used up.
- */
-class FastForwardSongIterator : public SongIterator {
-protected:
- SongIterator *_delegate;
- int _delta; /**!< Remaining time */
-
-public:
- FastForwardSongIterator(SongIterator *capsit, int delta);
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream();
- SongIterator *handleMessage(Message msg);
- int getTimepos();
- SongIterator *clone(int delta);
-};
-
-
-/**********************************/
-/*--------- Tee iterator ---------*/
-/**********************************/
-
-enum {
- TEE_LEFT = 0,
- TEE_RIGHT = 1,
- TEE_LEFT_ACTIVE = (1<<0),
- TEE_RIGHT_ACTIVE = (1<<1),
- TEE_LEFT_READY = (1<<2), /**!< left result is ready */
- TEE_RIGHT_READY = (1<<3), /**!< right result is ready */
- TEE_LEFT_PCM = (1<<4),
- TEE_RIGHT_PCM = (1<<5)
-};
-
-/**
- * This iterator combines two iterators, returns the next event available from either.
- */
-class TeeSongIterator : public SongIterator {
-public:
- int _status;
-
- bool _readyToMorph; /**!< One of TEE_MORPH_* above */
-
- struct {
- SongIterator *it;
- byte buf[4];
- int result;
- int retval;
- } _children[2];
-
-public:
- TeeSongIterator(SongIterator *left, SongIterator *right);
- ~TeeSongIterator();
-
- int nextCommand(byte *buf, int *result);
- Audio::AudioStream *getAudioStream();
- SongIterator *handleMessage(Message msg);
- void init();
- int getTimepos() { return 0; }
- SongIterator *clone(int delta);
-};
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
-
-#endif // SCI_SFX_SFX_ITERATOR_INTERNAL
diff --git a/engines/sci/sound/iterator/songlib.cpp b/engines/sci/sound/iterator/songlib.cpp
deleted file mode 100644
index 8bc2e8f476..0000000000
--- a/engines/sci/sound/iterator/songlib.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-#include "sci/sound/iterator/core.h"
-#include "sci/sound/iterator/iterator.h"
-
-namespace Sci {
-
-#define debug_stream stderr
-
-Song::Song() : _wakeupTime(0, SFX_TICKS_PER_SEC) {
- _handle = 0;
- _resourceNum = 0;
- _priority = 0;
- _status = SOUND_STATUS_STOPPED;
-
- _restoreBehavior = RESTORE_BEHAVIOR_CONTINUE;
- _restoreTime = 0;
-
- _loops = 0;
- _hold = 0;
-
- _it = 0;
- _delay = 0;
-
- _next = NULL;
- _nextPlaying = NULL;
- _nextStopping = NULL;
-}
-
-Song::Song(SongHandle handle, SongIterator *it, int priority) : _wakeupTime(0, SFX_TICKS_PER_SEC) {
- _handle = handle;
- _resourceNum = 0;
- _priority = priority;
- _status = SOUND_STATUS_STOPPED;
-
- _restoreBehavior = RESTORE_BEHAVIOR_CONTINUE;
- _restoreTime = 0;
-
- _loops = 0;
- _hold = 0;
-
- _it = it;
- _delay = 0;
-
- _next = NULL;
- _nextPlaying = NULL;
- _nextStopping = NULL;
-}
-
-void SongLibrary::addSong(Song *song) {
- Song **seeker = NULL;
- int pri = song->_priority;
-
- if (NULL == song) {
- warning("addSong(): NULL passed for song");
- return;
- }
-
- seeker = &_lib;
- while (*seeker && ((*seeker)->_priority > pri))
- seeker = &((*seeker)->_next);
-
- song->_next = *seeker;
- *seeker = song;
-}
-
-void SongLibrary::freeSounds() {
- Song *next = _lib;
- while (next) {
- Song *song = next;
- delete song->_it;
- song->_it = NULL;
- next = song->_next;
- delete song;
- }
- _lib = NULL;
-}
-
-
-Song *SongLibrary::findSong(SongHandle handle) {
- Song *seeker = _lib;
-
- while (seeker) {
- if (seeker->_handle == handle)
- break;
- seeker = seeker->_next;
- }
-
- return seeker;
-}
-
-Song *SongLibrary::findNextActive(Song *other) {
- Song *seeker = other ? other->_next : _lib;
-
- while (seeker) {
- if ((seeker->_status == SOUND_STATUS_WAITING) ||
- (seeker->_status == SOUND_STATUS_PLAYING))
- break;
- seeker = seeker->_next;
- }
-
- /* Only return songs that have equal priority */
- if (other && seeker && other->_priority > seeker->_priority)
- return NULL;
-
- return seeker;
-}
-
-Song *SongLibrary::findFirstActive() {
- return findNextActive(NULL);
-}
-
-int SongLibrary::removeSong(SongHandle handle) {
- int retval;
- Song *goner = _lib;
-
- if (!goner)
- return -1;
-
- if (goner->_handle == handle)
- _lib = goner->_next;
-
- else {
- while ((goner->_next) && (goner->_next->_handle != handle))
- goner = goner->_next;
-
- if (goner->_next) { /* Found him? */
- Song *oldnext = goner->_next;
-
- goner->_next = goner->_next->_next;
- goner = oldnext;
- } else return -1; /* No. */
- }
-
- retval = goner->_status;
-
- delete goner->_it;
- delete goner;
-
- return retval;
-}
-
-int SongLibrary::countSongs() {
- Song *seeker = _lib;
- int retval = 0;
-
- while (seeker) {
- retval++;
- seeker = seeker->_next;
- }
-
- return retval;
-}
-
-void SongLibrary::setSongRestoreBehavior(SongHandle handle, RESTORE_BEHAVIOR action) {
- Song *seeker = findSong(handle);
-
- seeker->_restoreBehavior = action;
-}
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
diff --git a/engines/sci/sound/iterator/songlib.h b/engines/sci/sound/iterator/songlib.h
deleted file mode 100644
index acb704edaa..0000000000
--- a/engines/sci/sound/iterator/songlib.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-/* Song library */
-
-#ifndef SCI_SFX_SFX_SONGLIB_H
-#define SCI_SFX_SFX_SONGLIB_H
-
-#include "common/scummsys.h"
-#include "sound/timestamp.h"
-
-#include "sci/sci.h" // for USE_OLD_MUSIC_FUNCTIONS
-#ifdef USE_OLD_MUSIC_FUNCTIONS
-
-namespace Sci {
-
-class SongIterator;
-
-#define SOUND_STATUS_STOPPED 0
-#define SOUND_STATUS_PLAYING 1
-#define SOUND_STATUS_SUSPENDED 2
-/* suspended: only if ordered from kernel space */
-#define SOUND_STATUS_WAITING 3
-/* "waiting" means "tagged for playing, but not active right now" */
-
-typedef unsigned long SongHandle;
-
-enum RESTORE_BEHAVIOR {
- RESTORE_BEHAVIOR_CONTINUE, /* restart a song when restored from
- a saved game */
- RESTORE_BEHAVIOR_RESTART /* continue it from where it was */
-};
-
-class Song {
-public:
- SongHandle _handle;
- int _resourceNum; /**<! Resource number */
- int _priority; /**!< Song priority (more important if priority is higher) */
- int _status; /* See above */
-
- int _restoreBehavior;
- int _restoreTime;
-
- /* Grabbed from the sound iterator, for save/restore purposes */
- int _loops;
- int _hold;
-
- SongIterator *_it;
- int _delay; /**!< Delay before accessing the iterator, in ticks */
-
- Audio::Timestamp _wakeupTime; /**!< Timestamp indicating the next MIDI event */
-
- Song *_next; /**!< Next song or NULL if this is the last one */
-
- /**
- * Next playing song. Used by the core song system.
- */
- Song *_nextPlaying;
-
- /**
- * Next song pending stopping. Used exclusively by the core song system's
- * _update_multi_song()
- */
- Song *_nextStopping;
-
-public:
-
- Song();
-
- /**
- * Initializes a new song.
- * @param handle the sound handle
- * @param it the song
- * @param priority the song's priority
- * @return a freshly allocated song
- */
- Song(SongHandle handle, SongIterator *it, int priority);
-};
-
-
-class SongLibrary {
-public:
- Song *_lib;
-
-public:
- SongLibrary() : _lib(0) {}
-
- /** Frees a song library. */
- void freeSounds();
-
- /**
- * Adds a song to a song library.
- * @param song song to add
- */
- void addSong(Song *song);
-
- /**
- * Looks up the song with the specified handle.
- * @param handle sound handle to look for
- * @return the song or NULL if it wasn't found
- */
- Song *findSong(SongHandle handle);
-
- /**
- * Finds the first song playing with the highest priority.
- * @return the song that should be played next, or NULL if there is none
- */
- Song *findFirstActive();
-
- /**
- * Finds the next song playing with the highest priority.
- *
- * The functions 'findFirstActive' and 'findNextActive'
- * allow to iterate over all songs that satisfy the requirement of
- * being 'playable'.
- *
- * @param song a song previously returned from the song library
- * @return the next song to play relative to 'song', or NULL if none are left
- */
- Song *findNextActive(Song *song);
-
- /**
- * Removes a song from the library.
- * @param handle handle of the song to remove
- * @return the status of the song that was removed
- */
- int removeSong(SongHandle handle);
-
- /**
- * Counts the number of songs in a song library.
- * @return the number of songs
- */
- int countSongs();
-
- /**
- * Determines what should be done with the song "handle" when restoring
- * it from a saved game.
- * @param handle sound handle being restored
- * @param action desired action
- */
- void setSongRestoreBehavior(SongHandle handle,
- RESTORE_BEHAVIOR action);
-};
-
-} // End of namespace Sci
-
-#endif // USE_OLD_MUSIC_FUNCTIONS
-
-#endif // SCI_SSFX_SFX_SONGLIB_H
diff --git a/engines/sci/sound/iterator/test-iterator.cpp b/engines/sci/sound/iterator/test-iterator.cpp
deleted file mode 100644
index 0d603a89fd..0000000000
--- a/engines/sci/sound/iterator/test-iterator.cpp
+++ /dev/null
@@ -1,423 +0,0 @@
-/* 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 2
- * 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "iterator.h"
-#include "iterator_internal.h"
-#include <stdarg.h>
-#include <stdio.h>
-
-using namespace Sci;
-
-#define ASSERT_S(x) if (!(x)) { error("Failed assertion in L%d: " #x, __LINE__); return; }
-#define ASSERT(x) ASSERT_S(x)
-
-/* Tests the song iterators */
-
-int errors = 0;
-
-void error(char *fmt, ...) {
- va_list ap;
-
- fprintf(stderr, "[ERROR] ");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- ++errors;
-}
-
-
-/* The simple iterator will finish after a fixed amount of time. Before that,
-** it emits (absolute) cues in ascending order. */
-struct simple_iterator : public SongIterator {
- int lifetime_remaining;
- char *cues;
- int cue_counter;
- int cue_progress;
- int cues_nr;
-};
-
-int simple_it_next(SongIterator *_self, unsigned char *buf, int *result) {
- simple_iterator *self = (simple_iterator *)_self;
-
- if (self->lifetime_remaining == -1) {
- error("Song iterator called post mortem");
- return SI_FINISHED;
- }
-
- if (self->lifetime_remaining) {
-
- if (self->cue_counter < self->cues_nr) {
- int time_to_cue = self->cues[self->cue_counter];
-
- if (self->cue_progress == time_to_cue) {
- ++self->cue_counter;
- self->cue_progress = 0;
- *result = self->cue_counter;
- return SI_ABSOLUTE_CUE;
- } else {
- int retval = time_to_cue - self->cue_progress;
- self->cue_progress = time_to_cue;
-
- if (retval > self->lifetime_remaining) {
- retval = self->lifetime_remaining;
- self->lifetime_remaining = 0;
- self->cue_progress = retval;
- return retval;
- }
-
- self->lifetime_remaining -= retval;
- return retval;
- }
- } else {
- int retval = self->lifetime_remaining;
- self->lifetime_remaining = 0;
- return retval;
- }
-
- } else {
- self->lifetime_remaining = -1;
- return SI_FINISHED;
- }
-}
-
-Audio::AudioStream *simple_it_pcm_feed(SongIterator *_self) {
- error("No PCM feed");
- return NULL;
-}
-
-void simple_it_init(SongIterator *_self) {
-}
-
-SongIterator *simple_it_handle_message(SongIterator *_self, SongIterator::Message msg) {
- return NULL;
-}
-
-void simple_it_cleanup(SongIterator *_self) {
-}
-
-/* Initialises the simple iterator.
-** Parameters: (int) delay: Number of ticks until the iterator finishes
-** (int *) cues: An array of cue delays (cue values are [1,2...])
-** (int) cues_nr: Number of cues in ``cues''
-** The first cue is emitted after cues[0] ticks, and it is 1. After cues[1] additional ticks
-** the next cue is emitted, and so on. */
-SongIterator *setup_simple_iterator(int delay, char *cues, int cues_nr) {
- simple_iterator.lifetime_remaining = delay;
- simple_iterator.cues = cues;
- simple_iterator.cue_counter = 0;
- simple_iterator.cues_nr = cues_nr;
- simple_iterator.cue_progress = 0;
-
- simple_iterator.ID = 42;
- simple_iterator.channel_mask = 0x004f;
- simple_iterator.flags = 0;
- simple_iterator.priority = 1;
-
- simple_iterator.death_listeners_nr = 0;
-
- simple_iterator.cleanup = simple_it_cleanup;
- simple_iterator.init = simple_it_init;
- simple_iterator.handle_message = simple_it_handle_message;
- simple_iterator.get_pcm_feed = simple_it_pcm_feed;
- simple_iterator.next = simple_it_next;
-
- return (SongIterator *) &simple_iterator;
-}
-
-#define ASSERT_SIT ASSERT(it == simple_it)
-#define ASSERT_FFIT ASSERT(it == ff_it)
-#define ASSERT_NEXT(n) ASSERT(songit_next(&it, data, &result, IT_READER_MASK_ALL) == n)
-#define ASSERT_RESULT(n) ASSERT(result == n)
-#define ASSERT_CUE(n) ASSERT_NEXT(SI_ABSOLUTE_CUE); ASSERT_RESULT(n)
-
-void test_simple_it() {
- SongIterator *it;
- SongIterator *simple_it = (SongIterator *) & simple_iterator;
- unsigned char data[4];
- int result;
- puts("[TEST] simple iterator (test artifact)");
-
- it = setup_simple_iterator(42, NULL, 0);
-
- ASSERT_SIT;
- ASSERT_NEXT(42);
- ASSERT_SIT;
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, "\003\004", 2);
- ASSERT_SIT;
- ASSERT_NEXT(3);
- ASSERT_CUE(1);
- ASSERT_SIT;
- ASSERT_NEXT(4);
- ASSERT_CUE(2);
- ASSERT_SIT;
-// warning("XXX => %d", songit_next(&it, data, &result, IT_READER_MASK_ALL));
- ASSERT_NEXT(35);
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- puts("[TEST] Test OK.");
-}
-
-void test_fastforward() {
- SongIterator *it;
- SongIterator *simple_it = (SongIterator *) & simple_iterator;
- SongIterator *ff_it;
- unsigned char data[4];
- int result;
- puts("[TEST] fast-forward iterator");
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 0);
- ASSERT_FFIT;
- ASSERT_NEXT(42);
- ASSERT_SIT; /* Must have morphed back */
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 1);
- ASSERT_FFIT;
- ASSERT_NEXT(41);
- /* May or may not have morphed back here */
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 41);
- ASSERT_FFIT;
- ASSERT_NEXT(1);
- /* May or may not have morphed back here */
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 42);
- ASSERT_NEXT(SI_FINISHED);
- /* May or may not have morphed back here */
-
- it = setup_simple_iterator(42, NULL, 0);
- ff_it = it = new_fast_forward_iterator(it, 10000);
- ASSERT_NEXT(SI_FINISHED);
- /* May or may not have morphed back here */
-
- it = setup_simple_iterator(42, "\003\004", 2);
- ff_it = it = new_fast_forward_iterator(it, 2);
- ASSERT_FFIT;
- ASSERT_NEXT(1);
- ASSERT_CUE(1);
- ASSERT_SIT;
- ASSERT_NEXT(4);
- ASSERT_CUE(2);
- ASSERT_SIT;
- ASSERT_NEXT(35);
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, "\003\004", 2);
- ff_it = it = new_fast_forward_iterator(it, 5);
- ASSERT_FFIT;
- ASSERT_CUE(1);
- ASSERT_FFIT;
- ASSERT_NEXT(2);
- ASSERT_CUE(2);
- ASSERT_SIT;
- ASSERT_NEXT(35);
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- it = setup_simple_iterator(42, "\003\004", 2);
- ff_it = it = new_fast_forward_iterator(it, 41);
- ASSERT_FFIT;
- ASSERT_CUE(1);
- ASSERT_FFIT;
- ASSERT_CUE(2);
- ASSERT_FFIT;
- ASSERT_NEXT(1);
- ASSERT_NEXT(SI_FINISHED);
- ASSERT_SIT;
-
- puts("[TEST] Test OK.");
-}
-
-#define SIMPLE_SONG_SIZE 50
-
-static unsigned char simple_song[SIMPLE_SONG_SIZE] = {
- 0x00, /* Regular song */
- /* Only use channel 0 for all devices */
- 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Song begins here */
- 42, 0x90, 60, 0x7f, /* Play C after 42 ticks */
- 02, 64, 0x42, /* Play E after 2 more ticks, using running status mode */
- 0xf8, 10, 0x80, 60, 0x02, /* Stop C after 250 ticks */
- 0, 64, 0x00, /* Stop E immediately */
- 00, 0xfc /* Stop song */
-};
-
-#define ASSERT_MIDI3(cmd, arg0, arg1) \
- ASSERT(data[0] == cmd); \
- ASSERT(data[1] == arg0); \
- ASSERT(data[2] == arg1);
-
-void test_iterator_sci0() {
- SongIterator *it = songit_new(simple_song, SIMPLE_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l);
- unsigned char data[4];
- int result;
- SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */
-
- puts("[TEST] SCI0-style song");
- ASSERT_NEXT(42);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 60, 0x7f);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(250);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 60, 0x02);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- ASSERT_NEXT(SI_FINISHED);
- puts("[TEST] Test OK.");
-}
-
-
-
-void test_iterator_sci0_loop() {
- SongIterator *it = songit_new(simple_song, SIMPLE_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l);
- unsigned char data[4];
- int result;
- SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */
- SIMSG_SEND(it, SIMSG_SET_LOOPS(2)); /* Loop one additional time */
-
- puts("[TEST] SCI0-style song with looping");
- ASSERT_NEXT(42);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 60, 0x7f);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(250);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 60, 0x02);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- ASSERT_NEXT(SI_LOOP);
- ASSERT_NEXT(42);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 60, 0x7f);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(250);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 60, 0x02);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- ASSERT_NEXT(SI_FINISHED);
- puts("[TEST] Test OK.");
-}
-
-
-
-#define LOOP_SONG_SIZE 54
-
-unsigned char loop_song[LOOP_SONG_SIZE] = {
- 0x00, /* Regular song song */
- /* Only use channel 0 for all devices */
- 0x02, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Song begins here */
- 42, 0x90, 60, 0x7f, /* Play C after 42 ticks */
- 13, 0x80, 60, 0x00, /* Stop C after 13 ticks */
- 00, 0xCF, 0x7f, /* Set loop point */
- 02, 0x90, 64, 0x42, /* Play E after 2 more ticks, using running status mode */
- 03, 0x80, 64, 0x00, /* Stop E after 3 ticks */
- 00, 0xfc /* Stop song/loop */
-};
-
-
-void test_iterator_sci0_mark_loop() {
- SongIterator *it = songit_new(loop_song, LOOP_SONG_SIZE, SCI_SONG_ITERATOR_TYPE_SCI0, 0l);
- unsigned char data[4];
- int result;
- SIMSG_SEND(it, SIMSG_SET_PLAYMASK(0x0001)); /* Initialise song, enabling channel 0 */
- SIMSG_SEND(it, SIMSG_SET_LOOPS(3)); /* Loop once more */
-
- puts("[TEST] SCI0-style song with loop mark, looping");
- ASSERT_NEXT(42);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 60, 0x7f);
- ASSERT_NEXT(13);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 60, 0x00);
- /* Loop point here: we don't observe that in the iterator interface yet, though */
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(3);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- /* Now we loop back to the loop pont */
- ASSERT_NEXT(SI_LOOP);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(3);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
- /* ...and one final time */
- ASSERT_NEXT(SI_LOOP);
- ASSERT_NEXT(2);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x90, 64, 0x42);
- ASSERT_NEXT(3);
- ASSERT_NEXT(0);
- ASSERT_MIDI3(0x80, 64, 0x00);
-
- ASSERT_NEXT(SI_FINISHED);
- puts("[TEST] Test OK.");
-}
-
-
-
-int main(int argc, char **argv) {
- test_simple_it();
- test_fastforward();
- test_iterator_sci0();
- test_iterator_sci0_loop();
- test_iterator_sci0_mark_loop();
- if (errors != 0)
- warning("[ERROR] %d errors total", errors);
- return (errors != 0);
-}
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index 053bf597f8..fa4804ce7d 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -844,7 +844,7 @@ void CharsetRendererClassic::printChar(int chr, bool ignoreCharsetMask) {
offsX = offsY = 0;
} else {
uint32 charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
- assert(charOffs < 0x10000);
+ assert(charOffs < 0x14000);
if (!charOffs)
return;
charPtr = _fontPtr + charOffs;
diff --git a/engines/scumm/debugger.cpp b/engines/scumm/debugger.cpp
index e0582f79ef..b5a4070f0b 100644
--- a/engines/scumm/debugger.cpp
+++ b/engines/scumm/debugger.cpp
@@ -868,7 +868,7 @@ bool ScummDebugger::Cmd_Passcode(int argc, const char **argv) {
detach();
} else {
- DebugPrintf("Use 'passcode <SEGA CD Passcode>'\n");
+ DebugPrintf("Current Passcode is %d \nUse 'passcode <SEGA CD Passcode>'\n",_vm->_scummVars[411]);
return true;
}
return false;
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index b160dac6f2..1e0bf6d4be 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -234,19 +234,6 @@ protected:
#endif
-class ConfigDialog : public GUI::OptionsDialog {
-protected:
-#ifdef SMALL_SCREEN_DEVICE
- GUI::Dialog *_keysDialog;
-#endif
-
-public:
- ConfigDialog();
- ~ConfigDialog();
-
- virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
-};
-
#pragma mark -
ScummDialog::ScummDialog(int x, int y, int w, int h) : GUI::Dialog(x, y, w, h) {
@@ -259,223 +246,31 @@ ScummDialog::ScummDialog(String name) : GUI::Dialog(name) {
#pragma mark -
-enum {
- kSaveCmd = 'SAVE',
- kLoadCmd = 'LOAD',
- kPlayCmd = 'PLAY',
- kOptionsCmd = 'OPTN',
- kHelpCmd = 'HELP',
- kAboutCmd = 'ABOU',
- kQuitCmd = 'QUIT',
- kChooseCmd = 'CHOS'
-};
-
-ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm)
- : ScummDialog("ScummMain"), _vm(scumm) {
-
- new GUI::ButtonWidget(this, "ScummMain.Resume", "Resume", kPlayCmd, 'P');
-
- _loadButton = new GUI::ButtonWidget(this, "ScummMain.Load", "Load", kLoadCmd, 'L');
- _saveButton = new GUI::ButtonWidget(this, "ScummMain.Save", "Save", kSaveCmd, 'S');
-
- new GUI::ButtonWidget(this, "ScummMain.Options", "Options", kOptionsCmd, 'O');
#ifndef DISABLE_HELP
- new GUI::ButtonWidget(this, "ScummMain.Help", "Help", kHelpCmd, 'H');
-#endif
- new GUI::ButtonWidget(this, "ScummMain.About", "About", kAboutCmd, 'A');
-
- new GUI::ButtonWidget(this, "ScummMain.Quit", "Quit", kQuitCmd, 'Q');
- //
- // Create the sub dialog(s)
- //
- _aboutDialog = new GUI::AboutDialog();
- _optionsDialog = new ConfigDialog();
-#ifndef DISABLE_HELP
+ScummMenuDialog::ScummMenuDialog(ScummEngine *scumm)
+ : MainMenuDialog(scumm) {
_helpDialog = new HelpDialog(scumm->_game);
-#endif
- _saveDialog = new GUI::SaveLoadChooser("Save game:", "Save");
- _saveDialog->setSaveMode(true);
- _loadDialog = new GUI::SaveLoadChooser("Load game:", "Load");
- _loadDialog->setSaveMode(false);
+ _helpButton->setEnabled(true);
}
ScummMenuDialog::~ScummMenuDialog() {
- delete _aboutDialog;
- delete _optionsDialog;
-#ifndef DISABLE_HELP
delete _helpDialog;
-#endif
- delete _saveDialog;
- delete _loadDialog;
-}
-
-int ScummMenuDialog::runModal() {
- _loadButton->setEnabled(_vm->canLoadGameStateCurrently());
- _saveButton->setEnabled(_vm->canSaveGameStateCurrently());
- return ScummDialog::runModal();
-}
-
-void ScummMenuDialog::reflowLayout() {
- _loadButton->setEnabled(_vm->canLoadGameStateCurrently());
- _saveButton->setEnabled(_vm->canSaveGameStateCurrently());
- Dialog::reflowLayout();
}
void ScummMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
- case kSaveCmd:
- save();
- break;
- case kLoadCmd:
- load();
- break;
- case kPlayCmd:
- close();
- break;
- case kOptionsCmd:
- _optionsDialog->runModal();
- break;
- case kAboutCmd:
- _aboutDialog->runModal();
- break;
-#ifndef DISABLE_HELP
case kHelpCmd:
_helpDialog->runModal();
break;
-#endif
- case kQuitCmd:
- _vm->quitGame();
- close();
- break;
default:
- ScummDialog::handleCommand(sender, cmd, data);
- }
-}
-
-void ScummMenuDialog::save() {
- Common::String gameId = ConfMan.get("gameid");
-
- const EnginePlugin *plugin = 0;
- EngineMan.findGame(gameId, &plugin);
-
- int idx = _saveDialog->runModal(plugin, ConfMan.getActiveDomainName());
- if (idx >= 0) {
- String result(_saveDialog->getResultString());
- char buffer[20];
- const char *str;
- if (result.empty()) {
- // If the user was lazy and entered no save name, come up with a default name.
- sprintf(buffer, "Save %d", idx);
- str = buffer;
- } else
- str = result.c_str();
- _vm->requestSave(idx, str);
- close();
- }
-}
-
-void ScummMenuDialog::load() {
- Common::String gameId = ConfMan.get("gameid");
-
- const EnginePlugin *plugin = 0;
- EngineMan.findGame(gameId, &plugin);
-
- int idx = _loadDialog->runModal(plugin, ConfMan.getActiveDomainName());
- if (idx >= 0) {
- _vm->requestLoad(idx);
- close();
+ MainMenuDialog::handleCommand(sender, cmd, data);
}
}
#pragma mark -
enum {
- kKeysCmd = 'KEYS'
-};
-
-// FIXME: We use the empty string as domain name here. This tells the
-// ConfigManager to use the 'default' domain for all its actions. We do that
-// to get as close as possible to editing the 'active' settings.
-//
-// However, that requires bad & evil hacks in the ConfigManager code,
-// and even then still doesn't work quite correctly.
-// For example, if the transient domain contains 'false' for the 'fullscreen'
-// flag, but the user used a hotkey to switch to windowed mode, then the dialog
-// will display the wrong value anyway.
-//
-// Proposed solution consisting of multiple steps:
-// 1) Add special code to the open() code that reads out everything stored
-// in the transient domain that is controlled by this dialog, and updates
-// the dialog accordingly.
-// 2) Even more code is added to query the backend for current settings, like
-// the fullscreen mode flag etc., and also updates the dialog accordingly.
-// 3) The domain being edited is set to the active game domain.
-// 4) If the dialog is closed with the "OK" button, then we remove everything
-// stored in the transient domain (or at least everything corresponding to
-// switches in this dialog.
-// If OTOH the dialog is closed with "Cancel" we do no such thing.
-//
-// These changes will achieve two things at once: Allow us to get rid of using
-// "" as value for the domain, and in fact provide a somewhat better user
-// experience at the same time.
-ConfigDialog::ConfigDialog()
- : GUI::OptionsDialog("", "ScummConfig") {
-
- //
- // Sound controllers
- //
-
- addVolumeControls(this, "ScummConfig.");
-
- //
- // Some misc options
- //
-
- // SCUMM has a talkspeed range of 0-9
- addSubtitleControls(this, "ScummConfig.", 9);
-
- //
- // Add the buttons
- //
-
- new GUI::ButtonWidget(this, "ScummConfig.Ok", "OK", GUI::kOKCmd, 'O');
- new GUI::ButtonWidget(this, "ScummConfig.Cancel", "Cancel", GUI::kCloseCmd, 'C');
-#ifdef SMALL_SCREEN_DEVICE
- new GUI::ButtonWidget(this, "ScummConfig.Keys", "Keys", kKeysCmd, 'K');
- _keysDialog = NULL;
-#endif
-}
-
-ConfigDialog::~ConfigDialog() {
-#ifdef SMALL_SCREEN_DEVICE
- delete _keysDialog;
-#endif
-}
-
-void ConfigDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
- switch (cmd) {
- case kKeysCmd:
-#ifdef SMALL_SCREEN_DEVICE
- //
- // Create the sub dialog(s)
- //
- _keysDialog = new GUI::KeysDialog();
- _keysDialog->runModal();
- delete _keysDialog;
- _keysDialog = NULL;
-#endif
- break;
- default:
- GUI::OptionsDialog::handleCommand (sender, cmd, data);
- }
-}
-
-#ifndef DISABLE_HELP
-
-#pragma mark -
-
-enum {
kNextCmd = 'NEXT',
kPrevCmd = 'PREV'
};
diff --git a/engines/scumm/dialogs.h b/engines/scumm/dialogs.h
index 7889027dcf..41a8ec83c1 100644
--- a/engines/scumm/dialogs.h
+++ b/engines/scumm/dialogs.h
@@ -27,9 +27,8 @@
#include "common/str.h"
#include "gui/dialog.h"
-#include "gui/options.h"
#include "gui/widget.h"
-#include "gui/saveload.h"
+#include "engines/dialogs.h"
#include "scumm/detection.h"
@@ -52,32 +51,17 @@ protected:
typedef Common::String String;
};
-class ScummMenuDialog : public ScummDialog {
+#ifndef DISABLE_HELP
+class ScummMenuDialog : public MainMenuDialog {
public:
ScummMenuDialog(ScummEngine *scumm);
~ScummMenuDialog();
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
- virtual void reflowLayout();
-
- int runModal();
protected:
- ScummEngine *_vm;
-
- GUI::Dialog *_aboutDialog;
- GUI::Dialog *_optionsDialog;
-#ifndef DISABLE_HELP
GUI::Dialog *_helpDialog;
-#endif
- GUI::SaveLoadChooser *_saveDialog;
- GUI::SaveLoadChooser *_loadDialog;
-
- GUI::ButtonWidget *_loadButton;
- GUI::ButtonWidget *_saveButton;
-
- void save();
- void load();
};
+#endif
/**
* A dialog which displays an arbitrary message to the user and returns
diff --git a/engines/scumm/he/resource_he.cpp b/engines/scumm/he/resource_he.cpp
index 886ee99e57..c259c3ffd2 100644
--- a/engines/scumm/he/resource_he.cpp
+++ b/engines/scumm/he/resource_he.cpp
@@ -633,8 +633,10 @@ Win32ResExtractor::WinResource *Win32ResExtractor::list_pe_resources(WinLibrary
wr[c].children = fi->first_resource + (FROM_LE_32(dirent[c].offset_to_data) & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY);
/* fill in wr->id, wr->numeric_id */
- if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name)))
+ if (!decode_pe_resource_id(fi, wr + c, FROM_LE_32(dirent[c].name))) {
+ free(wr);
return NULL;
+ }
}
return wr;
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp
index 8a9570f534..dc3a5d26b3 100644
--- a/engines/scumm/input.cpp
+++ b/engines/scumm/input.cpp
@@ -508,7 +508,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT), 0, 0, 0);
- scummMenuDialog(); // Display GUI
+ openMainMenuDialog(); // Display global main menu
if (VAR_SAVELOAD_SCRIPT != 0xFF && _currentRoom != 0)
runScript(VAR(VAR_SAVELOAD_SCRIPT2), 0, 0, 0);
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index dcbe4e6c0a..fc95060b6f 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -108,7 +108,7 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_language(dr.language),
_debugger(0),
_currentScript(0xFF), // Let debug() work on init stage
- _messageDialog(0), _pauseDialog(0), _scummMenuDialog(0), _versionDialog(0) {
+ _messageDialog(0), _pauseDialog(0), _versionDialog(0) {
if (_game.platform == Common::kPlatformNES) {
_gdi = new GdiNES(this);
@@ -140,7 +140,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_fileHandle = 0;
-
// Init all vars
_v0ObjectIndex = false;
_v0ObjectInInventory = false;
@@ -152,7 +151,6 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
_sound = NULL;
memset(&vm, 0, sizeof(vm));
_pauseDialog = NULL;
- _scummMenuDialog = NULL;
_versionDialog = NULL;
_fastMode = 0;
_actors = NULL;
@@ -552,6 +550,12 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
for (int i = 0; i < ARRAYSIZE(debugChannels); ++i)
DebugMan.addDebugChannel(debugChannels[i].flag, debugChannels[i].channel, debugChannels[i].desc);
+#ifndef DISABLE_HELP
+ // Create custom GMM dialog providing a help subdialog
+ assert(!_mainMenuDialog);
+ _mainMenuDialog = new ScummMenuDialog(this);
+#endif
+
g_eventRec.registerRandomSource(_rnd, "scumm");
}
@@ -572,7 +576,6 @@ ScummEngine::~ScummEngine() {
delete _charset;
delete _messageDialog;
delete _pauseDialog;
- delete _scummMenuDialog;
delete _versionDialog;
delete _fileHandle;
@@ -2444,13 +2447,6 @@ void ScummEngine::versionDialog() {
runDialog(*_versionDialog);
}
-void ScummEngine::scummMenuDialog() {
- if (!_scummMenuDialog)
- _scummMenuDialog = new ScummMenuDialog(this);
- runDialog(*_scummMenuDialog);
- syncSoundSettings();
-}
-
void ScummEngine::confirmExitDialog() {
ConfirmDialog d(this, 6);
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 885ab790de..42322ba5a2 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -530,7 +530,6 @@ protected:
Dialog *_pauseDialog;
Dialog *_messageDialog;
Dialog *_versionDialog;
- Dialog *_scummMenuDialog;
virtual int runDialog(Dialog &dialog);
void confirmExitDialog();
@@ -538,7 +537,6 @@ protected:
void pauseDialog();
void messageDialog(const char *message);
void versionDialog();
- void scummMenuDialog();
char displayMessage(const char *altButton, const char *message, ...) GCC_PRINTF(3, 4);
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index c0e7be7758..441e622184 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -23,7 +23,6 @@
*
*/
-
#include "common/file.h"
#include "sword1/sword1.h"
#include "sword1/animation.h"
@@ -72,6 +71,9 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSys
_bgSoundStream = NULL;
_decoderType = decoderType;
_decoder = decoder;
+
+ _white = 255;
+ _black = 0;
}
MoviePlayer::~MoviePlayer() {
@@ -254,9 +256,35 @@ bool MoviePlayer::playVideo() {
if (frame)
_vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
- if (_decoder->hasDirtyPalette())
+ if (_decoder->hasDirtyPalette()) {
_decoder->setSystemPalette();
+ uint32 maxWeight = 0;
+ uint32 minWeight = 0xFFFFFFFF;
+ uint32 weight;
+ byte r, g, b;
+
+ byte *palette = _decoder->getPalette();
+
+ for (int i = 0; i < 256; i++) {
+ r = *palette++;
+ g = *palette++;
+ b = *palette++;
+
+ weight = 3 * r * r + 6 * g * g + 2 * b * b;
+
+ if (weight >= maxWeight) {
+ maxWeight = weight;
+ _white = i;
+ }
+
+ if (weight <= minWeight) {
+ minWeight = weight;
+ _black = i;
+ }
+ }
+ }
+
Graphics::Surface *screen = _vm->_system->lockScreen();
performPostProcessing((byte *)screen->pixels);
_vm->_system->unlockScreen();
@@ -267,17 +295,19 @@ bool MoviePlayer::playVideo() {
while (_vm->_system->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
return false;
+
+ _vm->_system->delayMillis(10);
}
return !_vm->shouldQuit();
}
byte MoviePlayer::findBlackPalIndex() {
- return 0;
+ return _black;
}
byte MoviePlayer::findWhitePalIndex() {
- return 0xff;
+ return _white;
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h
index 82343f2800..193d5cf7ca 100644
--- a/engines/sword1/animation.h
+++ b/engines/sword1/animation.h
@@ -85,6 +85,7 @@ protected:
OSystem *_system;
Common::Array<MovieText *> _movieTexts;
int _textX, _textY, _textWidth, _textHeight;
+ byte _white, _black;
DecoderType _decoderType;
Graphics::VideoDecoder *_decoder;
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index c3f3e796b2..10895b2ec1 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -51,6 +51,9 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, A
_bgSoundStream = NULL;
_decoderType = decoderType;
_decoder = decoder;
+
+ _white = 255;
+ _black = 0;
}
MoviePlayer:: ~MoviePlayer() {
@@ -280,9 +283,35 @@ bool MoviePlayer::playVideo() {
if (frame)
_vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
- if (_decoder->hasDirtyPalette())
+ if (_decoder->hasDirtyPalette()) {
_decoder->setSystemPalette();
+ uint32 maxWeight = 0;
+ uint32 minWeight = 0xFFFFFFFF;
+ uint32 weight;
+ byte r, g, b;
+
+ byte *palette = _decoder->getPalette();
+
+ for (int i = 0; i < 256; i++) {
+ r = *palette++;
+ g = *palette++;
+ b = *palette++;
+
+ weight = 3 * r * r + 6 * g * g + 2 * b * b;
+
+ if (weight >= maxWeight) {
+ maxWeight = weight;
+ _white = i;
+ }
+
+ if (weight <= minWeight) {
+ minWeight = weight;
+ _black = i;
+ }
+ }
+ }
+
Graphics::Surface *screen = _vm->_system->lockScreen();
performPostProcessing((byte *)screen->pixels);
_vm->_system->unlockScreen();
@@ -293,17 +322,19 @@ bool MoviePlayer::playVideo() {
while (_vm->_system->getEventManager()->pollEvent(event))
if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
return false;
+
+ _vm->_system->delayMillis(10);
}
return !_vm->shouldQuit();
}
byte MoviePlayer::findBlackPalIndex() {
- return 0;
+ return _black;
}
byte MoviePlayer::findWhitePalIndex() {
- return 0xff;
+ return _white;
}
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index bbf83e264c..ee32b1d5f2 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -87,6 +87,7 @@ protected:
uint32 _currentMovieText;
byte *_textSurface;
int _textX, _textY;
+ byte _white, _black;
DecoderType _decoderType;
Graphics::VideoDecoder *_decoder;
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index df686f8bee..fdc4484a7c 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -284,7 +284,8 @@ void LoadFile(MEMHANDLE *pH) {
}
// extract and zero terminate the filename
- Common::strlcpy(szFilename, pH->szName, sizeof(pH->szName));
+ memcpy(szFilename, pH->szName, sizeof(pH->szName));
+ szFilename[sizeof(pH->szName)] = 0;
if (f.open(szFilename)) {
// read the data