Add Mohawk engine code. Part 2/3: common code changes.
svn-id: r46728
This commit is contained in:
parent
0ea022d076
commit
fb8ecae7f1
7 changed files with 124 additions and 27 deletions
|
@ -127,6 +127,9 @@ public:
|
||||||
#if PLUGIN_ENABLED_STATIC(MADE)
|
#if PLUGIN_ENABLED_STATIC(MADE)
|
||||||
LINK_PLUGIN(MADE)
|
LINK_PLUGIN(MADE)
|
||||||
#endif
|
#endif
|
||||||
|
#if PLUGIN_ENABLED_STATIC(MOHAWK)
|
||||||
|
LINK_PLUGIN(MOHAWK)
|
||||||
|
#endif
|
||||||
#if PLUGIN_ENABLED_STATIC(PARALLACTION)
|
#if PLUGIN_ENABLED_STATIC(PARALLACTION)
|
||||||
LINK_PLUGIN(PARALLACTION)
|
LINK_PLUGIN(PARALLACTION)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -95,7 +95,7 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
|
||||||
|
|
||||||
if (line.size() == 0) {
|
if (line.size() == 0) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else if (line[0] == '#') {
|
} else if (line[0] == '#' || line[0] == ';') {
|
||||||
// Accumulate comments here. Once we encounter either the start
|
// Accumulate comments here. Once we encounter either the start
|
||||||
// of a new section, or a key-value-pair, we associate the value
|
// of a new section, or a key-value-pair, we associate the value
|
||||||
// of the 'comment' variable with that entity.
|
// of the 'comment' variable with that entity.
|
||||||
|
@ -116,8 +116,8 @@ bool ConfigFile::loadFromStream(SeekableReadStream &stream) {
|
||||||
const char *p = line.c_str() + 1;
|
const char *p = line.c_str() + 1;
|
||||||
// Get the section name, and check whether it's valid (that
|
// Get the section name, and check whether it's valid (that
|
||||||
// is, verify that it only consists of alphanumerics,
|
// is, verify that it only consists of alphanumerics,
|
||||||
// dashes and underscores).
|
// periods, dashes and underscores).
|
||||||
while (*p && (isalnum(*p) || *p == '-' || *p == '_'))
|
while (*p && (isalnum(*p) || *p == '-' || *p == '_' || *p == '.'))
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
if (*p == '\0')
|
if (*p == '\0')
|
||||||
|
|
|
@ -388,6 +388,13 @@ public:
|
||||||
* err() or eos() to determine whether an exception occurred.
|
* err() or eos() to determine whether an exception occurred.
|
||||||
*/
|
*/
|
||||||
virtual String readLine();
|
virtual String readLine();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the beginning offset in the stream, which defaults to 0.
|
||||||
|
*
|
||||||
|
* @return the beginning offset of the stream
|
||||||
|
*/
|
||||||
|
virtual uint32 getBeginOffset() { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -447,6 +454,7 @@ public:
|
||||||
|
|
||||||
virtual int32 pos() const { return _pos - _begin; }
|
virtual int32 pos() const { return _pos - _begin; }
|
||||||
virtual int32 size() const { return _end - _begin; }
|
virtual int32 size() const { return _end - _begin; }
|
||||||
|
virtual uint32 getBeginOffset() { return _begin; }
|
||||||
|
|
||||||
virtual bool seek(int32 offset, int whence = SEEK_SET);
|
virtual bool seek(int32 offset, int whence = SEEK_SET);
|
||||||
};
|
};
|
||||||
|
|
1
configure
vendored
1
configure
vendored
|
@ -93,6 +93,7 @@ add_engine lol "Lands of Lore" no
|
||||||
add_engine lure "Lure of the Temptress" yes
|
add_engine lure "Lure of the Temptress" yes
|
||||||
add_engine m4 "M4/MADS" no
|
add_engine m4 "M4/MADS" no
|
||||||
add_engine made "MADE" yes
|
add_engine made "MADE" yes
|
||||||
|
add_engine mohawk "Mohawk" no
|
||||||
add_engine parallaction "Parallaction" yes
|
add_engine parallaction "Parallaction" yes
|
||||||
add_engine queen "Flight of the Amazon Queen" yes
|
add_engine queen "Flight of the Amazon Queen" yes
|
||||||
add_engine saga "SAGA" yes "ihnm saga2"
|
add_engine saga "SAGA" yes "ihnm saga2"
|
||||||
|
|
|
@ -84,6 +84,11 @@ DEFINES += -DENABLE_MADE=$(ENABLE_MADE)
|
||||||
MODULES += engines/made
|
MODULES += engines/made
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef ENABLE_MOHAWK
|
||||||
|
DEFINES += -DENABLE_MOHAWK=$(ENABLE_MOHAWK)
|
||||||
|
MODULES += engines/mohawk
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef ENABLE_PARALLACTION
|
ifdef ENABLE_PARALLACTION
|
||||||
DEFINES += -DENABLE_PARALLACTION=$(ENABLE_PARALLACTION)
|
DEFINES += -DENABLE_PARALLACTION=$(ENABLE_PARALLACTION)
|
||||||
MODULES += engines/parallaction
|
MODULES += engines/parallaction
|
||||||
|
|
125
sound/adpcm.cpp
125
sound/adpcm.cpp
|
@ -40,7 +40,7 @@ private:
|
||||||
int _channels;
|
int _channels;
|
||||||
typesADPCM _type;
|
typesADPCM _type;
|
||||||
uint32 _blockAlign;
|
uint32 _blockAlign;
|
||||||
uint32 _blockPos;
|
uint32 _blockPos[2];
|
||||||
uint8 _chunkPos;
|
uint8 _chunkPos;
|
||||||
uint16 _chunkData;
|
uint16 _chunkData;
|
||||||
int _blockLen;
|
int _blockLen;
|
||||||
|
@ -64,6 +64,9 @@ private:
|
||||||
int32 stepIndex;
|
int32 stepIndex;
|
||||||
} ima_ch[2];
|
} ima_ch[2];
|
||||||
|
|
||||||
|
// Apple QuickTime IMA ADPCM
|
||||||
|
int32 streamPos[2];
|
||||||
|
|
||||||
// MS ADPCM
|
// MS ADPCM
|
||||||
ADPCMChannelStatus ch[2];
|
ADPCMChannelStatus ch[2];
|
||||||
|
|
||||||
|
@ -94,6 +97,7 @@ public:
|
||||||
int readBufferTinsel4(int channels, int16 *buffer, const int numSamples);
|
int readBufferTinsel4(int channels, int16 *buffer, const int numSamples);
|
||||||
int readBufferTinsel6(int channels, int16 *buffer, const int numSamples);
|
int readBufferTinsel6(int channels, int16 *buffer, const int numSamples);
|
||||||
int readBufferTinsel8(int channels, int16 *buffer, const int numSamples);
|
int readBufferTinsel8(int channels, int16 *buffer, const int numSamples);
|
||||||
|
int readBufferApple(int16 *buffer, const int numSamples);
|
||||||
|
|
||||||
bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); }
|
bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); }
|
||||||
bool isStereo() const { return _channels == 2; }
|
bool isStereo() const { return _channels == 2; }
|
||||||
|
@ -135,7 +139,6 @@ ADPCMInputStream::ADPCMInputStream(Common::SeekableReadStream *stream, bool disp
|
||||||
_startpos = stream->pos();
|
_startpos = stream->pos();
|
||||||
_endpos = _startpos + size;
|
_endpos = _startpos + size;
|
||||||
_curLoop = 0;
|
_curLoop = 0;
|
||||||
_blockPos = 0;
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +150,9 @@ ADPCMInputStream::~ADPCMInputStream() {
|
||||||
void ADPCMInputStream::reset() {
|
void ADPCMInputStream::reset() {
|
||||||
memset(&_status, 0, sizeof(_status));
|
memset(&_status, 0, sizeof(_status));
|
||||||
_blockLen = 0;
|
_blockLen = 0;
|
||||||
_blockPos = _blockAlign; // To make sure first header is read
|
_blockPos[0] = _blockPos[1] = _blockAlign; // To make sure first header is read
|
||||||
|
_status.streamPos[0] = 0;
|
||||||
|
_status.streamPos[1] = _blockAlign;
|
||||||
_chunkPos = 0;
|
_chunkPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +183,9 @@ int ADPCMInputStream::readBuffer(int16 *buffer, const int numSamples) {
|
||||||
case kADPCMIma:
|
case kADPCMIma:
|
||||||
samplesDecoded = readBufferIMA(buffer, numSamples);
|
samplesDecoded = readBufferIMA(buffer, numSamples);
|
||||||
break;
|
break;
|
||||||
|
case kADPCMApple:
|
||||||
|
samplesDecoded = readBufferApple(buffer, numSamples);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error("Unsupported ADPCM encoding");
|
error("Unsupported ADPCM encoding");
|
||||||
break;
|
break;
|
||||||
|
@ -224,6 +232,77 @@ int ADPCMInputStream::readBufferIMA(int16 *buffer, const int numSamples) {
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ADPCMInputStream::readBufferApple(int16 *buffer, const int numSamples) {
|
||||||
|
// Need to write 2 samples per channel
|
||||||
|
assert(numSamples % (2 * _channels) == 0);
|
||||||
|
|
||||||
|
// Current sample positions
|
||||||
|
int samples[2] = { 0, 0};
|
||||||
|
// Current data bytes
|
||||||
|
byte data[2] = { 0, 0};
|
||||||
|
// Current nibble selectors
|
||||||
|
bool lowNibble[2] = {true, true};
|
||||||
|
|
||||||
|
// Number of samples per channel
|
||||||
|
int chanSamples = numSamples / _channels;
|
||||||
|
|
||||||
|
for (int i = 0; i < _channels; i++) {
|
||||||
|
_stream->seek(_status.streamPos[i]);
|
||||||
|
|
||||||
|
while ((samples[i] < chanSamples) &&
|
||||||
|
// Last byte read and a new one needed
|
||||||
|
!((_stream->eos() || (_stream->pos() >= _endpos)) && lowNibble[i])) {
|
||||||
|
|
||||||
|
if (_blockPos[i] == _blockAlign) {
|
||||||
|
// 2 byte header per block
|
||||||
|
uint16 temp = _stream->readUint16BE();
|
||||||
|
|
||||||
|
// First 9 bits are the upper bits of the predictor
|
||||||
|
_status.ima_ch[i].last = (int16) (temp & 0xFF80);
|
||||||
|
// Lower 7 bits are the step index
|
||||||
|
_status.ima_ch[i].stepIndex = temp & 0x007F;
|
||||||
|
|
||||||
|
// Clip the step index
|
||||||
|
_status.ima_ch[i].stepIndex = CLIP(_status.ima_ch[i].stepIndex, 0, 88);
|
||||||
|
|
||||||
|
_blockPos[i] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First decode the lower nibble, then the upper
|
||||||
|
if (lowNibble[i])
|
||||||
|
data[i] = _stream->readByte();
|
||||||
|
|
||||||
|
int16 sample;
|
||||||
|
if (lowNibble[i])
|
||||||
|
sample = decodeIMA(data[i] & 0x0F, i);
|
||||||
|
else
|
||||||
|
sample = decodeIMA(data[i] >> 4, i);
|
||||||
|
|
||||||
|
// The original is interleaved block-wise, we want it sample-wise
|
||||||
|
buffer[_channels * samples[i] + i] = sample;
|
||||||
|
|
||||||
|
samples[i]++;
|
||||||
|
|
||||||
|
// Different nibble
|
||||||
|
lowNibble[i] = !lowNibble[i];
|
||||||
|
|
||||||
|
// We're about to decode a new lower nibble again, so advance the block position
|
||||||
|
if (lowNibble[i])
|
||||||
|
_blockPos[i]++;
|
||||||
|
|
||||||
|
if (_channels == 2)
|
||||||
|
if (_blockPos[i] == _blockAlign)
|
||||||
|
// We're at the end of the block.
|
||||||
|
// Since the channels are interleaved, skip the next block
|
||||||
|
_stream->skip(MIN<uint32>(_blockAlign, _endpos - _stream->pos()));
|
||||||
|
|
||||||
|
_status.streamPos[i] = _stream->pos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return samples[0] + samples[1];
|
||||||
|
}
|
||||||
|
|
||||||
int ADPCMInputStream::readBufferMSIMA1(int16 *buffer, const int numSamples) {
|
int ADPCMInputStream::readBufferMSIMA1(int16 *buffer, const int numSamples) {
|
||||||
int samples = 0;
|
int samples = 0;
|
||||||
byte data;
|
byte data;
|
||||||
|
@ -231,16 +310,16 @@ int ADPCMInputStream::readBufferMSIMA1(int16 *buffer, const int numSamples) {
|
||||||
assert(numSamples % 2 == 0);
|
assert(numSamples % 2 == 0);
|
||||||
|
|
||||||
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
||||||
if (_blockPos == _blockAlign) {
|
if (_blockPos[0] == _blockAlign) {
|
||||||
// read block header
|
// read block header
|
||||||
_status.ima_ch[0].last = _stream->readSint16LE();
|
_status.ima_ch[0].last = _stream->readSint16LE();
|
||||||
_status.ima_ch[0].stepIndex = _stream->readSint16LE();
|
_status.ima_ch[0].stepIndex = _stream->readSint16LE();
|
||||||
_blockPos = 4;
|
_blockPos[0] = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; samples < numSamples && _blockPos < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
|
for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
|
||||||
data = _stream->readByte();
|
data = _stream->readByte();
|
||||||
_blockPos++;
|
_blockPos[0]++;
|
||||||
buffer[samples] = decodeIMA(data & 0x0f);
|
buffer[samples] = decodeIMA(data & 0x0f);
|
||||||
buffer[samples + 1] = decodeIMA((data >> 4) & 0x0f);
|
buffer[samples + 1] = decodeIMA((data >> 4) & 0x0f);
|
||||||
}
|
}
|
||||||
|
@ -288,7 +367,7 @@ int ADPCMInputStream::readBufferMS(int channels, int16 *buffer, const int numSam
|
||||||
samples = 0;
|
samples = 0;
|
||||||
|
|
||||||
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
||||||
if (_blockPos == _blockAlign) {
|
if (_blockPos[0] == _blockAlign) {
|
||||||
// read block header
|
// read block header
|
||||||
for (i = 0; i < channels; i++) {
|
for (i = 0; i < channels; i++) {
|
||||||
_status.ch[i].predictor = CLIP(_stream->readByte(), (byte)0, (byte)6);
|
_status.ch[i].predictor = CLIP(_stream->readByte(), (byte)0, (byte)6);
|
||||||
|
@ -308,12 +387,12 @@ int ADPCMInputStream::readBufferMS(int channels, int16 *buffer, const int numSam
|
||||||
for (i = 0; i < channels; i++)
|
for (i = 0; i < channels; i++)
|
||||||
buffer[samples++] = _status.ch[i].sample1;
|
buffer[samples++] = _status.ch[i].sample1;
|
||||||
|
|
||||||
_blockPos = channels * 7;
|
_blockPos[0] = channels * 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; samples < numSamples && _blockPos < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
|
for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
|
||||||
data = _stream->readByte();
|
data = _stream->readByte();
|
||||||
_blockPos++;
|
_blockPos[0]++;
|
||||||
buffer[samples] = decodeMS(&_status.ch[0], (data >> 4) & 0x0f);
|
buffer[samples] = decodeMS(&_status.ch[0], (data >> 4) & 0x0f);
|
||||||
buffer[samples + 1] = decodeMS(&_status.ch[channels - 1], data & 0x0f);
|
buffer[samples + 1] = decodeMS(&_status.ch[channels - 1], data & 0x0f);
|
||||||
}
|
}
|
||||||
|
@ -363,12 +442,12 @@ int ADPCMInputStream::readBufferTinsel4(int channels, int16 *buffer, const int n
|
||||||
assert(numSamples % 2 == 0);
|
assert(numSamples % 2 == 0);
|
||||||
|
|
||||||
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
||||||
if (_blockPos == _blockAlign) {
|
if (_blockPos[0] == _blockAlign) {
|
||||||
readBufferTinselHeader();
|
readBufferTinselHeader();
|
||||||
_blockPos = 0;
|
_blockPos[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; samples < numSamples && _blockPos < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2, _blockPos++) {
|
for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2, _blockPos[0]++) {
|
||||||
// Read 1 byte = 8 bits = two 4 bit blocks
|
// Read 1 byte = 8 bits = two 4 bit blocks
|
||||||
data = _stream->readByte();
|
data = _stream->readByte();
|
||||||
buffer[samples] = decodeTinsel((data << 8) & 0xF000, eVal);
|
buffer[samples] = decodeTinsel((data << 8) & 0xF000, eVal);
|
||||||
|
@ -386,13 +465,13 @@ int ADPCMInputStream::readBufferTinsel6(int channels, int16 *buffer, const int n
|
||||||
samples = 0;
|
samples = 0;
|
||||||
|
|
||||||
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
||||||
if (_blockPos == _blockAlign) {
|
if (_blockPos[0] == _blockAlign) {
|
||||||
readBufferTinselHeader();
|
readBufferTinselHeader();
|
||||||
_blockPos = 0;
|
_blockPos[0] = 0;
|
||||||
_chunkPos = 0;
|
_chunkPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; samples < numSamples && _blockPos < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _chunkPos = (_chunkPos + 1) % 4) {
|
for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _chunkPos = (_chunkPos + 1) % 4) {
|
||||||
|
|
||||||
switch (_chunkPos) {
|
switch (_chunkPos) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -402,17 +481,17 @@ int ADPCMInputStream::readBufferTinsel6(int channels, int16 *buffer, const int n
|
||||||
case 1:
|
case 1:
|
||||||
_chunkData = (_chunkData << 8) | (_stream->readByte());
|
_chunkData = (_chunkData << 8) | (_stream->readByte());
|
||||||
buffer[samples] = decodeTinsel((_chunkData << 6) & 0xFC00, eVal);
|
buffer[samples] = decodeTinsel((_chunkData << 6) & 0xFC00, eVal);
|
||||||
_blockPos++;
|
_blockPos[0]++;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
_chunkData = (_chunkData << 8) | (_stream->readByte());
|
_chunkData = (_chunkData << 8) | (_stream->readByte());
|
||||||
buffer[samples] = decodeTinsel((_chunkData << 4) & 0xFC00, eVal);
|
buffer[samples] = decodeTinsel((_chunkData << 4) & 0xFC00, eVal);
|
||||||
_blockPos++;
|
_blockPos[0]++;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
_chunkData = (_chunkData << 8);
|
_chunkData = (_chunkData << 8);
|
||||||
buffer[samples] = decodeTinsel((_chunkData << 2) & 0xFC00, eVal);
|
buffer[samples] = decodeTinsel((_chunkData << 2) & 0xFC00, eVal);
|
||||||
_blockPos++;
|
_blockPos[0]++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,12 +510,12 @@ int ADPCMInputStream::readBufferTinsel8(int channels, int16 *buffer, const int n
|
||||||
samples = 0;
|
samples = 0;
|
||||||
|
|
||||||
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
|
||||||
if (_blockPos == _blockAlign) {
|
if (_blockPos[0] == _blockAlign) {
|
||||||
readBufferTinselHeader();
|
readBufferTinselHeader();
|
||||||
_blockPos = 0;
|
_blockPos[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; samples < numSamples && _blockPos < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _blockPos++) {
|
for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _blockPos[0]++) {
|
||||||
// Read 1 byte = 8 bits = one 8 bit block
|
// Read 1 byte = 8 bits = one 8 bit block
|
||||||
data = _stream->readByte();
|
data = _stream->readByte();
|
||||||
buffer[samples] = decodeTinsel(data << 8, eVal);
|
buffer[samples] = decodeTinsel(data << 8, eVal);
|
||||||
|
|
|
@ -55,7 +55,8 @@ enum typesADPCM {
|
||||||
kADPCMTinsel4, // 4-bit ADPCM used by the Tinsel engine
|
kADPCMTinsel4, // 4-bit ADPCM used by the Tinsel engine
|
||||||
kADPCMTinsel6, // 6-bit ADPCM used by the Tinsel engine
|
kADPCMTinsel6, // 6-bit ADPCM used by the Tinsel engine
|
||||||
kADPCMTinsel8, // 8-bit ADPCM used by the Tinsel engine
|
kADPCMTinsel8, // 8-bit ADPCM used by the Tinsel engine
|
||||||
kADPCMIma // Standard IMA ADPCM
|
kADPCMIma, // Standard IMA ADPCM
|
||||||
|
kADPCMApple // Apple QuickTime IMA ADPCM
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue