aboutsummaryrefslogtreecommitdiff
path: root/engines/gob
diff options
context:
space:
mode:
authorSven Hesse2007-08-01 12:24:04 +0000
committerSven Hesse2007-08-01 12:24:04 +0000
commit35052de25feca6ff2a27c4f2434280939e20dd09 (patch)
treebc78733dd3cb5f927c0965e2ad98cd75a517e261 /engines/gob
parent5d7daad632f757621476e29b8de1ee47512948ba (diff)
downloadscummvm-rg350-35052de25feca6ff2a27c4f2434280939e20dd09.tar.gz
scummvm-rg350-35052de25feca6ff2a27c4f2434280939e20dd09.tar.bz2
scummvm-rg350-35052de25feca6ff2a27c4f2434280939e20dd09.zip
Support for (still a bit glitchy) 16bit sound
svn-id: r28383
Diffstat (limited to 'engines/gob')
-rw-r--r--engines/gob/coktelvideo.cpp158
-rw-r--r--engines/gob/coktelvideo.h15
2 files changed, 138 insertions, 35 deletions
diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp
index 864a760ea8..cd497293af 100644
--- a/engines/gob/coktelvideo.cpp
+++ b/engines/gob/coktelvideo.cpp
@@ -109,7 +109,7 @@ bool Imd::load(Common::SeekableReadStream &stream) {
// Sound
if (_features & kFeaturesSound) {
_soundFreq = _stream->readSint16LE();
- _soundSliceSize = _stream->readUint16LE();
+ _soundSliceSize = _stream->readSint16LE();
_soundSlicesCount = _stream->readSint16LE();
if (_soundFreq < 0)
@@ -540,6 +540,7 @@ CoktelVideo::State Imd::processFrame(uint16 frame) {
assert(soundBuf);
memset(soundBuf, 0, _soundSliceSize);
+
_audioStream->queueBuffer(soundBuf, _soundSliceSize);
}
}
@@ -819,6 +820,22 @@ void Imd::deLZ77(byte *dest, byte *src) {
}
}
+const uint16 Vmd::_tableDPCM[128] = {
+ 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080,
+ 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120,
+ 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0,
+ 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230,
+ 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280,
+ 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0,
+ 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320,
+ 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370,
+ 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0,
+ 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480,
+ 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700,
+ 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00,
+ 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000
+};
+
Vmd::Vmd() {
clear(false);
}
@@ -880,7 +897,7 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
}
_soundFreq = _stream->readSint16LE();
- _soundSliceSize = _stream->readUint16LE();
+ _soundSliceSize = _stream->readSint16LE();
_soundSlicesCount = _stream->readSint16LE();
_soundFlags = _stream->readUint16LE();
_hasSound = (_soundFreq != 0);
@@ -888,11 +905,26 @@ bool Vmd::load(Common::SeekableReadStream &stream) {
if (_hasSound) {
_features |= kFeaturesSound;
- _soundSliceLength = (uint16) (1000.0 / ((double) _soundFreq / (double) _soundSliceSize));
+ _soundStereo = (_soundFlags & 0x8000) ? 1 : ((_soundFlags & 0x200) ? 2 : 0);
+ if (_soundStereo > 0) {
+ warning("TODO: VMD stereo");
+ unload();
+ return false;
+ }
+
+ if (_soundSliceSize < 0) {
+ _soundBytesPerSample = 2;
+ _soundSliceSize = -_soundSliceSize;
+ }
+
+ _soundSliceLength = (uint16) (1000.0 /
+ ((double) _soundFreq / (double) _soundSliceSize));
+
_frameLength = _soundSliceLength;
_soundStage = 1;
- _audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0);
+ _audioStream = Audio::makeAppendableAudioStream(_soundFreq,
+ (_soundBytesPerSample == 2) ? Audio::Mixer::FLAG_16BITS : 0);
} else
_frameLength = 1000 / 12; // 12 FPS for a video without sound
@@ -1004,8 +1036,12 @@ void Vmd::clear(bool del) {
}
_hasVideo = true;
+
_partsPerFrame = 0;
_frames = 0;
+
+ _soundBytesPerSample = 1;
+ _soundStereo = 0;
}
CoktelVideo::State Vmd::processFrame(uint16 frame) {
@@ -1027,39 +1063,23 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) {
Part &part = _frames[frame].parts[i];
if (part.type == kPartTypeAudio) {
- byte *soundBuf;
-
// Next sound slice data
if (part.flags == 1) {
- if (_soundEnabled) {
- soundBuf = new byte[part.size];
- assert(soundBuf);
-
- _stream->read(soundBuf, part.size);
- unsignedToSigned(soundBuf, part.size);
-
- _audioStream->queueBuffer(soundBuf, part.size);
- } else
+ if (_soundEnabled)
+ filledSoundSlice(part.size);
+ else
_stream->skip(part.size);
// Initial sound data (all slices)
} else if (part.flags == 2) {
if (_soundEnabled) {
- _stream->skip(4); // Unknown
-
- soundBuf = new byte[part.size - 4];
- assert(soundBuf);
-
- _stream->read(soundBuf, part.size - 4);
- unsignedToSigned(soundBuf, part.size - 4);
+ uint32 mask = _stream->readUint32LE();
+ filledSoundSlices(part.size - 4, mask);
- _audioStream->queueBuffer(soundBuf, part.size - 4);
-
- if (_soundStage == 1) {
+ if (_soundStage == 1)
startSound = true;
- }
} else
_stream->skip(part.size);
@@ -1067,15 +1087,11 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) {
// Empty sound slice
} else if (part.flags == 3) {
- if (_soundEnabled && (part.size > 0)) {
- soundBuf = new byte[part.size];
- assert(soundBuf);
-
- memset(soundBuf, 0, part.size);
-
- _audioStream->queueBuffer(soundBuf, part.size);
- } else
+ if (_soundEnabled && (part.size > 0))
+ emptySoundSlice(part.size);
+ else
_stream->skip(part.size);
+
}
} else if (part.type == kPartTypeVideo) {
@@ -1194,4 +1210,78 @@ uint32 Vmd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) {
return 1;
}
+void Vmd::emptySoundSlice(uint32 size) {
+ byte *soundBuf = new byte[size];
+ assert(soundBuf);
+
+ memset(soundBuf, 0, size);
+
+ _audioStream->queueBuffer(soundBuf, size);
+}
+
+void Vmd::soundSlice8bit(uint32 size) {
+ byte *soundBuf = new byte[size];
+ assert(soundBuf);
+
+ _stream->read(soundBuf, size);
+ unsignedToSigned(soundBuf, size);
+
+ _audioStream->queueBuffer(soundBuf, size);
+}
+
+void Vmd::soundSlice16bit(uint32 size, int16 &init) {
+ byte *dataBuf = new byte[size];
+ byte *soundBuf = new byte[size * 2];
+
+ _stream->read(dataBuf, size);
+ deDPCM(soundBuf, dataBuf, init, size);
+ _audioStream->queueBuffer(soundBuf, size * 2);
+
+ delete[] dataBuf;
+}
+
+void Vmd::filledSoundSlice(uint32 size) {
+ if (_soundBytesPerSample == 1) {
+ soundSlice8bit(size);
+ } else if (_soundBytesPerSample == 2) {
+ int16 init = _stream->readSint16LE();
+ soundSlice16bit(size - 1, init);
+ }
+}
+
+void Vmd::filledSoundSlices(uint32 size, uint32 mask) {
+ if (_soundBytesPerSample == 1) {
+ soundSlice8bit(size);
+ return;
+ }
+
+ for (int i = 0; i < (_soundSlicesCount - 1); i++) {
+
+ if (mask & 1)
+ emptySoundSlice(_soundSliceSize * 2);
+ else {
+ int16 init = _stream->readSint16LE();
+ soundSlice16bit(_soundSliceSize, init);
+ }
+
+ mask >>= 1;
+ }
+
+}
+
+void Vmd::deDPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n) {
+ int16 *out = (int16 *) soundBuf;
+
+ int32 s = init;
+ for (uint32 i = 0; i < n; i++) {
+ if(dataBuf[i] & 0x80)
+ s -= _tableDPCM[dataBuf[i] & 0x7F];
+ else
+ s += _tableDPCM[dataBuf[i]];
+
+ s = CLIP(s, -32768, 32767);
+ *out++ = TO_BE_16(s);
+ }
+}
+
} // End of namespace Gob
diff --git a/engines/gob/coktelvideo.h b/engines/gob/coktelvideo.h
index 39228c7bca..a4e5452cce 100644
--- a/engines/gob/coktelvideo.h
+++ b/engines/gob/coktelvideo.h
@@ -225,7 +225,7 @@ protected:
uint16 _soundFlags;
int16 _soundFreq;
- uint16 _soundSliceSize;
+ int16 _soundSliceSize;
int16 _soundSlicesCount;
uint16 _soundSliceLength;
@@ -285,14 +285,27 @@ protected:
~Frame() { delete[] parts; }
} PACKED_STRUCT;
+ static const uint16 _tableDPCM[128];
+
bool _hasVideo;
+
uint16 _partsPerFrame;
Frame *_frames;
+ byte _soundBytesPerSample;
+ byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo)
+
void clear(bool del = true);
State processFrame(uint16 frame);
uint32 renderFrame(int16 left, int16 top, int16 right, int16 bottom);
+
+ void emptySoundSlice(uint32 size);
+ void soundSlice8bit(uint32 size);
+ void soundSlice16bit(uint32 size, int16 &init);
+ void filledSoundSlice(uint32 size);
+ void filledSoundSlices(uint32 size, uint32 mask);
+ void deDPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n);
};
} // End of namespace Gob