aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scumm/bundle.cpp30
-rw-r--r--scumm/imuse_digi.cpp381
-rw-r--r--scumm/imuse_digi.h37
-rw-r--r--scumm/resource.cpp5
-rw-r--r--scumm/saveload.cpp3
-rw-r--r--scumm/script_v8.cpp3
-rw-r--r--scumm/smush/insane.cpp1
-rw-r--r--scumm/smush/smush_player.cpp4
-rw-r--r--scumm/sound.cpp350
-rw-r--r--scumm/sound.h33
-rw-r--r--scumm/string.cpp3
11 files changed, 433 insertions, 417 deletions
diff --git a/scumm/bundle.cpp b/scumm/bundle.cpp
index cf0deae08a..6c78199f46 100644
--- a/scumm/bundle.cpp
+++ b/scumm/bundle.cpp
@@ -93,7 +93,7 @@ static const byte imxOtherTable[6][128] = {
}
};
-const byte imxShortTable[] = {
+static const byte imxShortTable[] = {
0, 0, 1, 3, 7, 15, 31, 63
};
@@ -436,12 +436,16 @@ int32 Bundle::getNumberOfMusicSamplesByName(const char *name) {
return number;
}
-#define NextBit bit = mask & 1; mask >>= 1; \
- if (!--bitsleft) { \
- mask = READ_LE_UINT16(srcptr); \
- srcptr += 2; \
- bitsleft = 16; \
- }
+#define NextBit \
+ do { \
+ bit = mask & 1; \
+ mask >>= 1; \
+ if (!--bitsleft) { \
+ mask = READ_LE_UINT16(srcptr); \
+ srcptr += 2; \
+ bitsleft = 16; \
+ } \
+ } while (0)
static int32 compDecode(byte *src, byte *dst) {
byte *result, *srcptr = src, *dstptr = dst;
@@ -449,12 +453,16 @@ static int32 compDecode(byte *src, byte *dst) {
srcptr += 2;
while (1) {
- NextBit if (bit) {
+ NextBit;
+ if (bit) {
*dstptr++ = *srcptr++;
} else {
- NextBit if (!bit) {
- NextBit size = bit << 1;
- NextBit size = (size | bit) + 3;
+ NextBit;
+ if (!bit) {
+ NextBit;
+ size = bit << 1;
+ NextBit;
+ size = (size | bit) + 3;
data = *srcptr++ | 0xffffff00;
} else {
data = *srcptr++;
diff --git a/scumm/imuse_digi.cpp b/scumm/imuse_digi.cpp
index b4ee1386d5..980f2a2254 100644
--- a/scumm/imuse_digi.cpp
+++ b/scumm/imuse_digi.cpp
@@ -20,6 +20,8 @@
#include "stdafx.h"
#include "common/timer.h"
+#include "scumm/actor.h"
+#include "scumm/bundle.h"
#include "scumm/imuse_digi.h"
#include "scumm/scumm.h"
#include "scumm/sound.h"
@@ -684,6 +686,37 @@ static byte *readCreativeVocFile(byte *ptr, int32 &size, int &rate) {
return ret_sound;
}
+static uint32 decode12BitsSample(byte *src, byte **dst, uint32 size, bool stereo) {
+ uint32 s_size = (size / 3) * 4;
+ uint32 loop_size = s_size / 4;
+ if (stereo) {
+ s_size *= 2;
+ }
+ byte *ptr = *dst = (byte *)malloc(s_size);
+
+ uint32 tmp;
+ while (loop_size--) {
+ byte v1 = *src++;
+ byte v2 = *src++;
+ byte v3 = *src++;
+ tmp = ((((v2 & 0x0f) << 8) | v1) << 4) - 0x8000;
+ *ptr++ = (byte)((tmp >> 8) & 0xff);
+ *ptr++ = (byte)(tmp & 0xff);
+ if (stereo) {
+ *ptr++ = (byte)((tmp >> 8) & 0xff);
+ *ptr++ = (byte)(tmp & 0xff);
+ }
+ tmp = ((((v2 & 0xf0) << 4) | v3) << 4) - 0x8000;
+ *ptr++ = (byte)((tmp >> 8) & 0xff);
+ *ptr++ = (byte)(tmp & 0xff);
+ if (stereo) {
+ *ptr++ = (byte)((tmp >> 8) & 0xff);
+ *ptr++ = (byte)(tmp & 0xff);
+ }
+ }
+ return s_size;
+}
+
void IMuseDigital::timer_handler(void *refCon) {
IMuseDigital *imuseDigital = (IMuseDigital *)refCon;
imuseDigital->musicTimer();
@@ -697,6 +730,13 @@ IMuseDigital::IMuseDigital(ScummEngine *scumm)
}
_scumm->_timer->installTimerProc(timer_handler, 200000, this);
_pause = false;
+
+ _nameBundleMusic = "";
+ _musicBundleBufFinal = NULL;
+ _musicBundleBufOutput = NULL;
+ _musicDisk = 0;
+
+ _bundle = new Bundle();
}
IMuseDigital::~IMuseDigital() {
@@ -705,6 +745,8 @@ IMuseDigital::~IMuseDigital() {
for (int l = 0; l < MAX_DIGITAL_CHANNELS; l++) {
_scumm->_mixer->stopHandle(_channel[l]._handle);
}
+
+ delete _bundle;
}
void IMuseDigital::musicTimer() {
@@ -883,7 +925,7 @@ void IMuseDigital::startSound(int sound) {
if (_channel[l]._bits == 12) {
_channel[l]._mixerSize *= 2;
_channel[l]._mixerFlags |= SoundMixer::FLAG_16BITS;
- _channel[l]._size = _scumm->_sound->decode12BitsSample(ptr, &_channel[l]._data, size, (_channel[l]._channels == 2) ? false : true);
+ _channel[l]._size = decode12BitsSample(ptr, &_channel[l]._data, size, (_channel[l]._channels == 2) ? false : true);
} else if (_channel[l]._bits == 8) {
_channel[l]._mixerFlags |= SoundMixer::FLAG_UNSIGNED;
if (_channel[l]._channels == 1) {
@@ -928,6 +970,7 @@ void IMuseDigital::stopAllSounds() {
void IMuseDigital::pause(bool p) {
_pause = p;
+ pauseBundleMusic(p);
}
int32 IMuseDigital::doCommand(int a, int b, int c, int d, int e, int f, int g, int h) {
@@ -1041,7 +1084,7 @@ int32 IMuseDigital::doCommand(int a, int b, int c, int d, int e, int f, int g, i
}
if (_scumm->_gameId == GID_DIG) {
if (b == 1000) { // STATE_NULL
- _scumm->_sound->stopBundleMusic();
+ stopBundleMusic();
return 0;
}
for (l = 0;; l++) {
@@ -1052,30 +1095,30 @@ int32 IMuseDigital::doCommand(int a, int b, int c, int d, int e, int f, int g, i
int music = _digStateMusicMap[l].table_index;
debug(5, "Play imuse music: %s, %s, %s", _digStateMusicTable[music].name, _digStateMusicTable[music].title, _digStateMusicTable[music].filename);
if ((_digStateMusicTable[music].filename[0] != 0) &&
- (strcmp(_digStateMusicTable[_digStateMusicTable[music].unk3].filename, _scumm->_sound->_nameBundleMusic) != 0) ) {
- _scumm->_sound->playBundleMusic(_digStateMusicTable[music].filename);
+ (strcmp(_digStateMusicTable[_digStateMusicTable[music].unk3].filename, _nameBundleMusic) != 0) ) {
+ playBundleMusic(_digStateMusicTable[music].filename);
}
return 0;
}
}
} else if ((_scumm->_gameId == GID_CMI) && (_scumm->_features & GF_DEMO)) {
if (b == 2) {
- _scumm->_sound->playBundleMusic("in1.imx");
+ playBundleMusic("in1.imx");
} else if (b == 4) {
- _scumm->_sound->playBundleMusic("in2.imx");
+ playBundleMusic("in2.imx");
} else if (b == 8) {
- _scumm->_sound->playBundleMusic("out1.imx");
+ playBundleMusic("out1.imx");
} else if (b == 9) {
- _scumm->_sound->playBundleMusic("out2.imx");
+ playBundleMusic("out2.imx");
} else if (b == 16) {
- _scumm->_sound->playBundleMusic("gun.imx");
+ playBundleMusic("gun.imx");
} else {
warning("imuse digital: set state unknown for cmi demo: %d, room: %d", b, this->_scumm->_currentRoom);
return 1;
}
} else if (_scumm->_gameId == GID_CMI) {
if (b == 1000) { // STATE_NULL
- _scumm->_sound->stopBundleMusic();
+ stopBundleMusic();
return 0;
}
for (l = 0;; l++) {
@@ -1085,7 +1128,7 @@ int32 IMuseDigital::doCommand(int a, int b, int c, int d, int e, int f, int g, i
if ((_comiStateMusicTable[l].id == b)) {
debug(5, "Play imuse music: %s, %s, %s", _comiStateMusicTable[l].name, _comiStateMusicTable[l].title, _comiStateMusicTable[l].filename);
if (_comiStateMusicTable[l].filename[0] != 0) {
- _scumm->_sound->playBundleMusic(_comiStateMusicTable[l].filename);
+ playBundleMusic(_comiStateMusicTable[l].filename);
}
return 0;
}
@@ -1119,7 +1162,7 @@ int32 IMuseDigital::doCommand(int a, int b, int c, int d, int e, int f, int g, i
if ((_digSeqMusicTable[l].room == b)) {
debug(5, "Play imuse music: %s, %s, %s", _digSeqMusicTable[l].name, _digSeqMusicTable[l].title, _digSeqMusicTable[l].filename);
if (_digSeqMusicTable[l].filename[0] != 0) {
- _scumm->_sound->playBundleMusic(_digSeqMusicTable[l].filename);
+ playBundleMusic(_digSeqMusicTable[l].filename);
}
return 0;
}
@@ -1132,7 +1175,7 @@ int32 IMuseDigital::doCommand(int a, int b, int c, int d, int e, int f, int g, i
if ((_comiSeqMusicTable[l].id == b)) {
debug(5, "Play imuse music: %s, %s, %s", _comiSeqMusicTable[l].name, _comiSeqMusicTable[l].title, _comiSeqMusicTable[l].filename);
if (_comiSeqMusicTable[l].filename[0] != 0) {
- _scumm->_sound->playBundleMusic(_comiSeqMusicTable[l].filename);
+ playBundleMusic(_comiSeqMusicTable[l].filename);
}
return 0;
}
@@ -1188,6 +1231,318 @@ int IMuseDigital::getSoundStatus(int sound) const {
return 0;
}
+#pragma mark -
+
+void IMuseDigital::music_handler(void *refCon) {
+ ((IMuseDigital *)refCon)->bundleMusicHandler();
+}
+
+void IMuseDigital::playBundleMusic(const char *song) {
+ if (_scumm->_silentDigitalImuse) {
+ return;
+ }
+
+ if (_nameBundleMusic[0] == 0) {
+ if (_scumm->_gameId == GID_CMI) {
+ _outputMixerSize = (22050 * 2 * 2);
+
+ char bunfile[20];
+ if (_scumm->_features & GF_DEMO) {
+ if (_bundle->openMusicFile("music.bun", _scumm->getGameDataPath()) == false) {
+ _outputMixerSize = 0;
+ return;
+ }
+ } else {
+
+ sprintf(bunfile, "musdisk%d.bun", _scumm->VAR(_scumm->VAR_CURRENTDISK));
+ if (_musicDisk != _scumm->VAR(_scumm->VAR_CURRENTDISK))
+ _bundle->closeMusicFile();
+
+ if (_bundle->openMusicFile(bunfile, _scumm->getGameDataPath()) == false) {
+ if (_bundle->openMusicFile("music.bun", _scumm->getGameDataPath()) == false) {
+ _outputMixerSize = 0;
+ return;
+ }
+ }
+
+ _musicDisk = (byte)_scumm->VAR(_scumm->VAR_CURRENTDISK);
+ }
+ } else {
+ _outputMixerSize = ((22050 * 2 * 2) / 4) * 3;
+
+ if (_bundle->openMusicFile("digmusic.bun", _scumm->getGameDataPath()) == false)
+ return;
+ }
+ _musicBundleBufFinal = (byte *)malloc(_outputMixerSize);
+ _musicBundleBufOutput = (byte *)malloc(((_outputMixerSize / 0x2000) + 1) * _outputMixerSize);
+ _currentSampleBundleMusic = 0;
+ _offsetSampleBundleMusic = 0;
+ _offsetBufBundleMusic = 0;
+ _bundleMusicPosition = 0;
+ _bundleSongPosInMs = 0;
+ _pauseBundleMusic = false;
+ _musicBundleToBeChanged = false;
+ _bundleMusicTrack = 0;
+ _numberSamplesBundleMusic = _bundle->getNumberOfMusicSamplesByName(song);
+ _nameBundleMusic = song;
+ _scumm->_timer->installTimerProc(&music_handler, 1000000, this);
+ } else if (strcmp(_nameBundleMusic, song) != 0) {
+ _newNameBundleMusic = song;
+ _musicBundleToBeChanged = true;
+ }
+}
+
+void IMuseDigital::pauseBundleMusic(bool state) {
+ _pauseBundleMusic = state;
+}
+
+void IMuseDigital::stopBundleMusic() {
+ // First stop the music timer
+ _scumm->_timer->removeTimerProc(&music_handler);
+ _nameBundleMusic = "";
+ _scumm->_mixer->stopHandle(_bundleMusicTrack);
+ if (_musicBundleBufFinal) {
+ free(_musicBundleBufFinal);
+ _musicBundleBufFinal = NULL;
+ }
+ if (_musicBundleBufOutput) {
+ free(_musicBundleBufOutput);
+ _musicBundleBufOutput = NULL;
+ }
+}
+
+void IMuseDigital::bundleMusicHandler() {
+ byte *ptr;
+ int32 l, num = _numberSamplesBundleMusic, length, k;
+ int32 rate = 22050;
+ int32 tag, size = -1, header_size = 0;
+
+ if (_pauseBundleMusic)
+ return;
+
+ if (_musicBundleToBeChanged) {
+ _nameBundleMusic = _newNameBundleMusic;
+ _numberSamplesBundleMusic = _bundle->getNumberOfMusicSamplesByName(_nameBundleMusic);
+ _currentSampleBundleMusic = 0;
+ _offsetSampleBundleMusic = 0;
+ _offsetBufBundleMusic = 0;
+ _musicBundleToBeChanged = false;
+ _bundleMusicPosition = 0;
+ _bundleSongPosInMs = 0;
+ }
+
+ ptr = _musicBundleBufOutput;
+
+ for (k = 0, l = _currentSampleBundleMusic; l < num; k++) {
+ length = _bundle->decompressMusicSampleByName(_nameBundleMusic, l, (_musicBundleBufOutput + ((k * 0x2000) + _offsetBufBundleMusic)));
+ _offsetSampleBundleMusic += length;
+
+ if (l == 0) {
+ tag = READ_BE_UINT32(ptr); ptr += 4;
+ if (tag != MKID_BE('iMUS')) {
+ error("Decompressing bundle song failed (unknown tag '%s')", tag2str(tag));
+ }
+
+ ptr += 12;
+ while (tag != MKID_BE('DATA')) {
+ tag = READ_BE_UINT32(ptr); ptr += 4;
+ switch(tag) {
+ case MKID_BE('FRMT'):
+ ptr += 12;
+ _bundleMusicSampleBits = READ_BE_UINT32(ptr); ptr += 4;
+ rate = READ_BE_UINT32(ptr); ptr += 4;
+ _bundleSampleChannels = READ_BE_UINT32(ptr); ptr += 4;
+ break;
+ case MKID_BE('TEXT'):
+ case MKID_BE('REGN'):
+ case MKID_BE('STOP'):
+ case MKID_BE('JUMP'):
+ case MKID_BE('SYNC'):
+ size = READ_BE_UINT32(ptr); ptr += size + 4;
+ break;
+ case MKID_BE('DATA'):
+ size = READ_BE_UINT32(ptr); ptr += 4;
+ break;
+
+ default:
+ error("Unknown sound header %c%c%c%c",
+ (byte)(tag >> 24),
+ (byte)(tag >> 16),
+ (byte)(tag >> 8),
+ (byte)tag);
+ }
+ }
+ if (size < 0) {
+ error("Decompressing sound failed (missing size field)");
+ }
+ header_size = (ptr - _musicBundleBufOutput);
+ }
+
+ l++;
+ _currentSampleBundleMusic = l;
+
+ if (_offsetSampleBundleMusic >= _outputMixerSize + header_size) {
+ memcpy(_musicBundleBufFinal, (_musicBundleBufOutput + header_size), _outputMixerSize);
+ _offsetBufBundleMusic = _offsetSampleBundleMusic - _outputMixerSize - header_size;
+ memcpy(_musicBundleBufOutput, (_musicBundleBufOutput + (_outputMixerSize + header_size)), _offsetBufBundleMusic);
+ _offsetSampleBundleMusic = _offsetBufBundleMusic;
+ break;
+ }
+ }
+
+ if (_currentSampleBundleMusic == num) {
+ _currentSampleBundleMusic = 0;
+ _offsetSampleBundleMusic = 0;
+ _offsetBufBundleMusic = 0;
+ _bundleMusicPosition = 0;
+ _bundleSongPosInMs = 0;
+ }
+
+ ptr = _musicBundleBufFinal;
+
+ byte *buffer = NULL;
+ uint32 final_size;
+ if (_bundleMusicSampleBits == 12) {
+ final_size = decode12BitsSample(ptr, &buffer, _outputMixerSize, false);
+ } else if (_bundleMusicSampleBits == 16) {
+ buffer = (byte *)malloc(_outputMixerSize);
+ final_size = _outputMixerSize;
+ memcpy(buffer, ptr, _outputMixerSize);
+ } else {
+ warning("IMuseDigital::bundleMusicHandler TODO: more newStream options...");
+ return;
+ }
+
+ _bundleSongPosInMs = (_bundleMusicPosition * 5) / (_outputMixerSize / 200);
+ _bundleMusicPosition += final_size;
+ if (_bundleMusicTrack == 0)
+ _scumm->_mixer->newStream(&_bundleMusicTrack, rate, SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO, 300000);
+ _scumm->_mixer->appendStream(_bundleMusicTrack, buffer, final_size);
+ free(buffer);
+}
+
+void IMuseDigital::playBundleSound(const char *sound, PlayingSoundHandle *handle) {
+ byte *ptr = 0, *orig_ptr = 0;
+ byte *final;
+ bool result;
+
+ if (_scumm->_noDigitalSamples)
+ return;
+
+ if (_scumm->_gameId == GID_CMI) {
+ if (_scumm->_features & GF_DEMO) {
+ result = _bundle->openVoiceFile("voice.bun", _scumm->getGameDataPath());
+ } else {
+ char voxfile[20];
+ sprintf(voxfile, "voxdisk%d.bun", _scumm->VAR(_scumm->VAR_CURRENTDISK));
+ if (_voiceDisk != _scumm->VAR(_scumm->VAR_CURRENTDISK))
+ _bundle->closeVoiceFile();
+
+ result = _bundle->openVoiceFile(voxfile, _scumm->getGameDataPath());
+
+ if (result == false)
+ result = _bundle->openVoiceFile("voice.bun", _scumm->getGameDataPath());
+ _voiceDisk = (byte)_scumm->VAR(_scumm->VAR_CURRENTDISK);
+ }
+ } else if (_scumm->_gameId == GID_DIG)
+ result = _bundle->openVoiceFile("digvoice.bun", _scumm->getGameDataPath());
+ else
+ error("Don't know which bundle file to load");
+
+ if (!result)
+ return;
+
+ int32 rate = 22050, pan = 0, channels, output_size = 0;
+ int32 tag, size = -1, bits = 0;
+
+ if (_scumm->_gameId == GID_CMI) {
+ char name[20];
+ strcpy(name, sound);
+ if (!(_scumm->_features & GF_DEMO)) // CMI demo does not have .IMX for voice but does for music...
+ strcat(name, ".IMX");
+ output_size = _bundle->decompressVoiceSampleByName(name, &ptr);
+ } else {
+ output_size = _bundle->decompressVoiceSampleByName(sound, &ptr);
+ }
+
+ orig_ptr = ptr;
+ if (output_size == 0 || orig_ptr == 0) {
+ goto bail;
+ }
+
+ tag = READ_BE_UINT32(ptr); ptr += 4;
+ if (tag != MKID_BE('iMUS')) {
+ warning("Decompression of bundle sound failed");
+ goto bail;
+ }
+
+ ptr += 12;
+ while (tag != MKID_BE('DATA')) {
+ tag = READ_BE_UINT32(ptr); ptr += 4;
+ switch(tag) {
+ case MKID_BE('FRMT'):
+ ptr += 12;
+ bits = READ_BE_UINT32(ptr); ptr += 4;
+ rate = READ_BE_UINT32(ptr); ptr += 4;
+ channels = READ_BE_UINT32(ptr); ptr += 4;
+ break;
+ case MKID_BE('TEXT'):
+ case MKID_BE('REGN'):
+ case MKID_BE('STOP'):
+ case MKID_BE('JUMP'):
+ case MKID_BE('SYNC'):
+ size = READ_BE_UINT32(ptr); ptr += size + 4;
+ break;
+ case MKID_BE('DATA'):
+ size = READ_BE_UINT32(ptr); ptr += 4;
+ break;
+ default:
+ error("Unknown sound header %c%c%c%c",
+ (byte)(tag >> 24),
+ (byte)(tag >> 16),
+ (byte)(tag >> 8),
+ (byte)tag);
+ }
+ }
+
+ if (size < 0) {
+ warning("Decompression sound failed (no size field)");
+ goto bail;
+ }
+
+ final = (byte *)malloc(size);
+ memcpy(final, ptr, size);
+
+ if (_scumm->_actorToPrintStrFor != 0xFF && _scumm->_actorToPrintStrFor != 0) {
+ Actor *a = _scumm->derefActor(_scumm->_actorToPrintStrFor, "playBundleSound");
+ rate = (rate * a->talkFrequency) / 256;
+
+ // Adjust to fit the mixer's notion of panning.
+ if (pan != 64)
+ pan = 2 * a->talkPan - 127;
+ }
+
+ // Stop any sound currently playing on the given handle
+ if (handle)
+ _scumm->_mixer->stopHandle(*handle);
+
+ if (bits == 8) {
+ _scumm->_mixer->playRaw(handle, final, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE, -1, 255, pan);
+ } else if (bits == 16) {
+ // FIXME: For some weird reasons, sometimes we get an odd size, even though
+ // the data is supposed to be in 16 bit format... that makes no sense...
+ size &= ~1;
+ _scumm->_mixer->playRaw(handle, final, size, rate, SoundMixer::FLAG_16BITS | SoundMixer::FLAG_AUTOFREE, -1, 255, pan);
+ } else {
+ warning("IMuseDigital::playBundleSound() to do more options to playRaw...");
+ }
+
+bail:
+ free(orig_ptr);
+}
+
+
+
} // End of namespace Scumm
#ifdef __PALM_OS__
diff --git a/scumm/imuse_digi.h b/scumm/imuse_digi.h
index 620eea16e5..161f27e10f 100644
--- a/scumm/imuse_digi.h
+++ b/scumm/imuse_digi.h
@@ -34,6 +34,7 @@ namespace Scumm {
#define MAX_IMUSE_REGIONS 3
class ScummEngine;
+class Bundle;
/**
* iMuse Digital Implementation for SCUMM v7 and higher.
@@ -68,9 +69,43 @@ private:
ScummEngine *_scumm;
bool _pause;
- static void timer_handler(void *engine);
+ static void timer_handler(void *refConf);
void musicTimer();
+ //
+ // Bundle music
+ //
+ const char *_nameBundleMusic;
+ const char *_newNameBundleMusic;
+ byte _musicDisk;
+ byte _voiceDisk;
+ int32 _currentSampleBundleMusic;
+ int32 _numberSamplesBundleMusic;
+ int32 _offsetSampleBundleMusic;
+ int32 _offsetBufBundleMusic;
+ byte *_musicBundleBufFinal;
+ byte *_musicBundleBufOutput;
+ bool _pauseBundleMusic;
+ PlayingSoundHandle _bundleMusicTrack;
+ bool _musicBundleToBeChanged;
+ int32 _bundleMusicSampleBits;
+ int32 _outputMixerSize;
+ int32 _bundleSampleChannels;
+ int32 _bundleMusicPosition;
+
+ static void music_handler(void *refCon);
+ void bundleMusicHandler();
+
+ void playBundleMusic(const char *song);
+ void pauseBundleMusic(bool state);
+
+public:
+ int32 _bundleSongPosInMs;
+ Bundle *_bundle; // FIXME: should be protected but is used by ScummEngine::askForDisk
+
+ void stopBundleMusic();
+ void playBundleSound(const char *sound, PlayingSoundHandle *handle);
+
public:
IMuseDigital(ScummEngine *scumm);
~IMuseDigital();
diff --git a/scumm/resource.cpp b/scumm/resource.cpp
index 471a2cd52e..ea62be8b22 100644
--- a/scumm/resource.cpp
+++ b/scumm/resource.cpp
@@ -26,6 +26,7 @@
#include "scumm/bundle.h"
#include "scumm/dialogs.h"
#include "scumm/imuse.h"
+#include "scumm/imuse_digi.h"
#include "scumm/object.h"
#include "scumm/resource.h"
#include "scumm/scumm.h"
@@ -227,8 +228,8 @@ void ScummEngine::askForDisk(const char *filename, int disknum) {
if (_version == 8) {
char result;
- _sound->_bundle->closeVoiceFile();
- _sound->_bundle->closeMusicFile();
+ _imuseDigital->_bundle->closeVoiceFile();
+ _imuseDigital->_bundle->closeMusicFile();
#ifdef MACOSX
sprintf(buf, "Cannot find file: '%s'\nPlease insert disc %d.\nHit OK to retry, Cancel to exit", filename, disknum);
diff --git a/scumm/saveload.cpp b/scumm/saveload.cpp
index f9fbdc9430..d477063ef5 100644
--- a/scumm/saveload.cpp
+++ b/scumm/saveload.cpp
@@ -126,7 +126,8 @@ bool ScummEngine::loadState(int slot, bool compat, SaveFileManager *mgr) {
memcpy(_saveLoadName, hdr.name, sizeof(hdr.name));
_sound->stopAllSounds();
- _sound->stopBundleMusic();
+ if (_imuseDigital)
+ _imuseDigital->stopBundleMusic();
_sound->stopCD();
_sound->pauseSounds(true);
diff --git a/scumm/script_v8.cpp b/scumm/script_v8.cpp
index 5a45b9f8eb..123451ca8d 100644
--- a/scumm/script_v8.cpp
+++ b/scumm/script_v8.cpp
@@ -24,6 +24,7 @@
#include "scumm/actor.h"
#include "scumm/akos.h"
#include "scumm/charset.h"
+#include "scumm/imuse_digi.h"
#include "scumm/intern.h"
#include "scumm/object.h"
#include "scumm/resource.h"
@@ -1483,7 +1484,7 @@ void ScummEngine_v8::o8_kernelGetFunctions() {
case 0xE1: // imGetMusicPosition
warning("o8_kernelGetFunctions: imGetMusicPosition(stub)");
// FIXME - get this stuff to be properly implemented
- push(_sound->_bundleSongPosInMs);
+ push(_imuseDigital->_bundleSongPosInMs);
break;
case 0xE2: // musicLipSyncWidth
case 0xE3: // musicLipSyncHeight
diff --git a/scumm/smush/insane.cpp b/scumm/smush/insane.cpp
index e65281be1e..b247dc4c79 100644
--- a/scumm/smush/insane.cpp
+++ b/scumm/smush/insane.cpp
@@ -8213,7 +8213,6 @@ void Insane::smush_setupSanFile(const char *filename, int32 offset) {
_player->seekSan(filename, _scumm->getGameDataPath(), offset);
_scumm->_imuseDigital->pause(false);
- _scumm->_sound->pauseBundleMusic(false);
}
}
diff --git a/scumm/smush/smush_player.cpp b/scumm/smush/smush_player.cpp
index 36396eb515..8028d5eff7 100644
--- a/scumm/smush/smush_player.cpp
+++ b/scumm/smush/smush_player.cpp
@@ -244,7 +244,6 @@ void SmushPlayer::init() {
_frame = 0;
- _scumm->_sound->pauseBundleMusic(true);
if (_scumm->_imuseDigital) {
_scumm->_imuseDigital->pause(true);
}
@@ -293,7 +292,6 @@ void SmushPlayer::deinit() {
if (_scumm->_imuseDigital) {
_scumm->_imuseDigital->pause(false);
}
- _scumm->_sound->pauseBundleMusic(false);
_scumm->_fullRedraw = true;
}
@@ -373,7 +371,7 @@ void SmushPlayer::handleIACT(Chunk &b) {
checkBlock(b, TYPE_IACT, 8);
debug(6, "SmushPlayer::handleImuseAction()");
- int code = b.getWord();
+ /* int code = */ b.getWord();
int flags = b.getWord();
int unknown = b.getShort();
int track_flags = b.getWord();
diff --git a/scumm/sound.cpp b/scumm/sound.cpp
index 06be1f4673..ce475a4ad7 100644
--- a/scumm/sound.cpp
+++ b/scumm/sound.cpp
@@ -22,7 +22,6 @@
#include "stdafx.h"
#include "scumm/actor.h"
-#include "scumm/bundle.h"
#include "scumm/imuse.h"
#include "scumm/imuse_digi.h"
#include "scumm/scumm.h"
@@ -57,21 +56,14 @@ Sound::Sound(ScummEngine *parent) {
memset(this,0,sizeof(Sound)); // palmos
_scumm = parent;
- _nameBundleMusic = "";
- _musicBundleBufFinal = NULL;
- _musicBundleBufOutput = NULL;
- _musicDisk = 0;
_talkChannelHandle = 0;
_currentCDSound = 0;
_sfxFile = 0;
-
- _bundle = new Bundle();
}
Sound::~Sound() {
delete _sfxFile;
- delete _bundle;
}
void Sound::addSoundToQueue(int sound) {
@@ -821,8 +813,6 @@ void Sound::pauseSounds(bool pause) {
_scumm->_mixer->pauseAll(pause);
- _scumm->_sound->pauseBundleMusic(pause);
-
if (_scumm->_imuseDigital) {
_scumm->_imuseDigital->pause(pause);
}
@@ -978,346 +968,6 @@ bool Sound::isSfxFinished() const {
return !_scumm->_mixer->hasActiveSFXChannel();
}
-uint32 Sound::decode12BitsSample(byte *src, byte **dst, uint32 size, bool stereo) {
- uint32 s_size = (size / 3) * 4;
- uint32 loop_size = s_size / 4;
- if (stereo) {
- s_size *= 2;
- }
- byte *ptr = *dst = (byte *)malloc(s_size);
-
- uint32 tmp;
- while (loop_size--) {
- byte v1 = *src++;
- byte v2 = *src++;
- byte v3 = *src++;
- tmp = ((((v2 & 0x0f) << 8) | v1) << 4) - 0x8000;
- *ptr++ = (byte)((tmp >> 8) & 0xff);
- *ptr++ = (byte)(tmp & 0xff);
- if (stereo) {
- *ptr++ = (byte)((tmp >> 8) & 0xff);
- *ptr++ = (byte)(tmp & 0xff);
- }
- tmp = ((((v2 & 0xf0) << 4) | v3) << 4) - 0x8000;
- *ptr++ = (byte)((tmp >> 8) & 0xff);
- *ptr++ = (byte)(tmp & 0xff);
- if (stereo) {
- *ptr++ = (byte)((tmp >> 8) & 0xff);
- *ptr++ = (byte)(tmp & 0xff);
- }
- }
- return s_size;
-}
-
-static void music_handler(void *refCon) {
- Sound *sound = (Sound *)refCon;
- sound->bundleMusicHandler(g_scumm);
-}
-
-void Sound::playBundleMusic(const char *song) {
- if (_scumm->_silentDigitalImuse) {
- return;
- }
-
- if (_nameBundleMusic[0] == 0) {
- if (_scumm->_gameId == GID_CMI) {
- _outputMixerSize = (22050 * 2 * 2);
-
- char bunfile[20];
- if (_scumm->_features & GF_DEMO) {
- if (_bundle->openMusicFile("music.bun", _scumm->getGameDataPath()) == false) {
- _outputMixerSize = 0;
- return;
- }
- } else {
-
- sprintf(bunfile, "musdisk%d.bun", _scumm->VAR(_scumm->VAR_CURRENTDISK));
- if (_musicDisk != _scumm->VAR(_scumm->VAR_CURRENTDISK))
- _bundle->closeMusicFile();
-
- if (_bundle->openMusicFile(bunfile, _scumm->getGameDataPath()) == false) {
- if (_bundle->openMusicFile("music.bun", _scumm->getGameDataPath()) == false) {
- _outputMixerSize = 0;
- return;
- }
- }
-
- _musicDisk = (byte)_scumm->VAR(_scumm->VAR_CURRENTDISK);
- }
- } else {
- _outputMixerSize = ((22050 * 2 * 2) / 4) * 3;
-
- if (_bundle->openMusicFile("digmusic.bun", _scumm->getGameDataPath()) == false)
- return;
- }
- _musicBundleBufFinal = (byte *)malloc(_outputMixerSize);
- _musicBundleBufOutput = (byte *)malloc(((_outputMixerSize / 0x2000) + 1) * _outputMixerSize);
- _currentSampleBundleMusic = 0;
- _offsetSampleBundleMusic = 0;
- _offsetBufBundleMusic = 0;
- _bundleMusicPosition = 0;
- _bundleSongPosInMs = 0;
- _pauseBundleMusic = false;
- _musicBundleToBeChanged = false;
- _bundleMusicTrack = 0;
- _numberSamplesBundleMusic = _bundle->getNumberOfMusicSamplesByName(song);
- _nameBundleMusic = song;
- _scumm->_timer->installTimerProc(&music_handler, 1000000, this);
- } else if (strcmp(_nameBundleMusic, song) != 0) {
- _newNameBundleMusic = song;
- _musicBundleToBeChanged = true;
- }
-}
-
-void Sound::pauseBundleMusic(bool state) {
- _pauseBundleMusic = state;
-}
-
-void Sound::stopBundleMusic() {
- // First stop the music timer
- _scumm->_timer->removeTimerProc(&music_handler);
- _nameBundleMusic = "";
- _scumm->_mixer->stopHandle(_bundleMusicTrack);
- if (_musicBundleBufFinal) {
- free(_musicBundleBufFinal);
- _musicBundleBufFinal = NULL;
- }
- if (_musicBundleBufOutput) {
- free(_musicBundleBufOutput);
- _musicBundleBufOutput = NULL;
- }
-}
-
-void Sound::bundleMusicHandler(ScummEngine *scumm) {
- byte *ptr;
- int32 l, num = _numberSamplesBundleMusic, length, k;
- int32 rate = 22050;
- int32 tag, size = -1, header_size = 0;
-
- if (_pauseBundleMusic)
- return;
-
- if (_musicBundleToBeChanged) {
- _nameBundleMusic = _newNameBundleMusic;
- _numberSamplesBundleMusic = _bundle->getNumberOfMusicSamplesByName(_nameBundleMusic);
- _currentSampleBundleMusic = 0;
- _offsetSampleBundleMusic = 0;
- _offsetBufBundleMusic = 0;
- _musicBundleToBeChanged = false;
- _bundleMusicPosition = 0;
- _bundleSongPosInMs = 0;
- }
-
- ptr = _musicBundleBufOutput;
-
- for (k = 0, l = _currentSampleBundleMusic; l < num; k++) {
- length = _bundle->decompressMusicSampleByName(_nameBundleMusic, l, (_musicBundleBufOutput + ((k * 0x2000) + _offsetBufBundleMusic)));
- _offsetSampleBundleMusic += length;
-
- if (l == 0) {
- tag = READ_BE_UINT32(ptr); ptr += 4;
- if (tag != MKID_BE('iMUS')) {
- error("Decompressing bundle song failed (unknown tag '%s')", tag2str(tag));
- }
-
- ptr += 12;
- while (tag != MKID_BE('DATA')) {
- tag = READ_BE_UINT32(ptr); ptr += 4;
- switch(tag) {
- case MKID_BE('FRMT'):
- ptr += 12;
- _bundleMusicSampleBits = READ_BE_UINT32(ptr); ptr += 4;
- rate = READ_BE_UINT32(ptr); ptr += 4;
- _bundleSampleChannels = READ_BE_UINT32(ptr); ptr += 4;
- break;
- case MKID_BE('TEXT'):
- case MKID_BE('REGN'):
- case MKID_BE('STOP'):
- case MKID_BE('JUMP'):
- case MKID_BE('SYNC'):
- size = READ_BE_UINT32(ptr); ptr += size + 4;
- break;
- case MKID_BE('DATA'):
- size = READ_BE_UINT32(ptr); ptr += 4;
- break;
-
- default:
- error("Unknown sound header %c%c%c%c",
- (byte)(tag >> 24),
- (byte)(tag >> 16),
- (byte)(tag >> 8),
- (byte)tag);
- }
- }
- if (size < 0) {
- error("Decompressing sound failed (missing size field)");
- }
- header_size = (ptr - _musicBundleBufOutput);
- }
-
- l++;
- _currentSampleBundleMusic = l;
-
- if (_offsetSampleBundleMusic >= _outputMixerSize + header_size) {
- memcpy(_musicBundleBufFinal, (_musicBundleBufOutput + header_size), _outputMixerSize);
- _offsetBufBundleMusic = _offsetSampleBundleMusic - _outputMixerSize - header_size;
- memcpy(_musicBundleBufOutput, (_musicBundleBufOutput + (_outputMixerSize + header_size)), _offsetBufBundleMusic);
- _offsetSampleBundleMusic = _offsetBufBundleMusic;
- break;
- }
- }
-
- if (_currentSampleBundleMusic == num) {
- _currentSampleBundleMusic = 0;
- _offsetSampleBundleMusic = 0;
- _offsetBufBundleMusic = 0;
- _bundleMusicPosition = 0;
- _bundleSongPosInMs = 0;
- }
-
- ptr = _musicBundleBufFinal;
-
- byte *buffer = NULL;
- uint32 final_size;
- if (_bundleMusicSampleBits == 12) {
- final_size = decode12BitsSample(ptr, &buffer, _outputMixerSize, false);
- } else if (_bundleMusicSampleBits == 16) {
- buffer = (byte *)malloc(_outputMixerSize);
- final_size = _outputMixerSize;
- memcpy(buffer, ptr, _outputMixerSize);
- } else {
- warning("Sound::bundleMusicHandler TODO: more newStream options...");
- return;
- }
-
- _bundleSongPosInMs = (_bundleMusicPosition * 5) / (_outputMixerSize / 200);
- _bundleMusicPosition += final_size;
- if (_bundleMusicTrack == 0)
- _scumm->_mixer->newStream(&_bundleMusicTrack, rate, SoundMixer::FLAG_16BITS | SoundMixer::FLAG_STEREO, 300000);
- _scumm->_mixer->appendStream(_bundleMusicTrack, buffer, final_size);
- free(buffer);
-}
-
-void Sound::playBundleSound(char *sound, PlayingSoundHandle *handle) {
- byte *ptr = 0, *orig_ptr = 0;
- byte *final;
- bool result;
-
- if (_scumm->_noDigitalSamples)
- return;
-
- if (_scumm->_gameId == GID_CMI) {
- if (_scumm->_features & GF_DEMO) {
- result = _bundle->openVoiceFile("voice.bun", _scumm->getGameDataPath());
- } else {
- char voxfile[20];
- sprintf(voxfile, "voxdisk%d.bun", _scumm->VAR(_scumm->VAR_CURRENTDISK));
- if (_voiceDisk != _scumm->VAR(_scumm->VAR_CURRENTDISK))
- _bundle->closeVoiceFile();
-
- result = _bundle->openVoiceFile(voxfile, _scumm->getGameDataPath());
-
- if (result == false)
- result = _bundle->openVoiceFile("voice.bun", _scumm->getGameDataPath());
- _voiceDisk = (byte)_scumm->VAR(_scumm->VAR_CURRENTDISK);
- }
- } else if (_scumm->_gameId == GID_DIG)
- result = _bundle->openVoiceFile("digvoice.bun", _scumm->getGameDataPath());
- else
- error("Don't know which bundle file to load");
-
- if (!result)
- return;
-
- int32 rate = 22050, pan = 0, channels, output_size = 0;
- int32 tag, size = -1, bits = 0;
-
- if (_scumm->_gameId == GID_CMI) {
- char name[20];
- strcpy(name, sound);
- if (!(_scumm->_features & GF_DEMO)) // CMI demo does not have .IMX for voice but does for music...
- strcat(name, ".IMX");
- output_size = _bundle->decompressVoiceSampleByName(name, &ptr);
- } else {
- output_size = _bundle->decompressVoiceSampleByName(sound, &ptr);
- }
-
- orig_ptr = ptr;
- if (output_size == 0 || orig_ptr == 0) {
- goto bail;
- }
-
- tag = READ_BE_UINT32(ptr); ptr += 4;
- if (tag != MKID_BE('iMUS')) {
- warning("Decompression of bundle sound failed");
- goto bail;
- }
-
- ptr += 12;
- while (tag != MKID_BE('DATA')) {
- tag = READ_BE_UINT32(ptr); ptr += 4;
- switch(tag) {
- case MKID_BE('FRMT'):
- ptr += 12;
- bits = READ_BE_UINT32(ptr); ptr += 4;
- rate = READ_BE_UINT32(ptr); ptr += 4;
- channels = READ_BE_UINT32(ptr); ptr += 4;
- break;
- case MKID_BE('TEXT'):
- case MKID_BE('REGN'):
- case MKID_BE('STOP'):
- case MKID_BE('JUMP'):
- case MKID_BE('SYNC'):
- size = READ_BE_UINT32(ptr); ptr += size + 4;
- break;
- case MKID_BE('DATA'):
- size = READ_BE_UINT32(ptr); ptr += 4;
- break;
- default:
- error("Unknown sound header %c%c%c%c",
- (byte)(tag >> 24),
- (byte)(tag >> 16),
- (byte)(tag >> 8),
- (byte)tag);
- }
- }
-
- if (size < 0) {
- warning("Decompression sound failed (no size field)");
- goto bail;
- }
-
- final = (byte *)malloc(size);
- memcpy(final, ptr, size);
-
- if (_scumm->_actorToPrintStrFor != 0xFF && _scumm->_actorToPrintStrFor != 0) {
- Actor *a = _scumm->derefActor(_scumm->_actorToPrintStrFor, "playBundleSound");
- rate = (rate * a->talkFrequency) / 256;
-
- // Adjust to fit the mixer's notion of panning.
- if (pan != 64)
- pan = 2 * a->talkPan - 127;
- }
-
- // Stop any sound currently playing on the given handle
- if (handle)
- _scumm->_mixer->stopHandle(*handle);
-
- if (bits == 8) {
- _scumm->_mixer->playRaw(handle, final, size, rate, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE, -1, 255, pan);
- } else if (bits == 16) {
- // FIXME: For some weird reasons, sometimes we get an odd size, even though
- // the data is supposed to be in 16 bit format... that makes no sense...
- size &= ~1;
- _scumm->_mixer->playRaw(handle, final, size, rate, SoundMixer::FLAG_16BITS | SoundMixer::FLAG_AUTOFREE, -1, 255, pan);
- } else {
- warning("Sound::playBundleSound() to do more options to playRaw...");
- }
-
-bail:
- free(orig_ptr);
-}
-
void Sound::playSfxSound(void *sound, uint32 size, uint rate, bool isUnsigned, PlayingSoundHandle *handle) {
byte flags = SoundMixer::FLAG_AUTOFREE;
if (isUnsigned)
diff --git a/scumm/sound.h b/scumm/sound.h
index e1b6c7c64d..263208c304 100644
--- a/scumm/sound.h
+++ b/scumm/sound.h
@@ -28,7 +28,6 @@ class File;
namespace Scumm {
-class Bundle;
class ScummEngine;
struct MP3OffsetTable;
@@ -38,28 +37,6 @@ protected:
int16 _soundQuePos, _soundQue[0x100];
int16 _soundQue2Pos, _soundQue2[10];
-public:
- const char *_nameBundleMusic;
- int32 _bundleMusicPosition;
- int32 _bundleSongPosInMs;
-
-protected:
- const char *_newNameBundleMusic;
- byte _musicDisk;
- byte _voiceDisk;
- int32 _currentSampleBundleMusic;
- int32 _numberSamplesBundleMusic;
- int32 _offsetSampleBundleMusic;
- int32 _offsetBufBundleMusic;
- byte *_musicBundleBufFinal;
- byte *_musicBundleBufOutput;
- bool _pauseBundleMusic;
- PlayingSoundHandle _bundleMusicTrack;
- bool _musicBundleToBeChanged;
- int32 _bundleMusicSampleBits;
- int32 _outputMixerSize;
- int32 _bundleSampleChannels;
-
File *_sfxFile;
uint32 _talk_sound_a1, _talk_sound_a2, _talk_sound_b1, _talk_sound_b2;
byte _talk_sound_mode;
@@ -81,8 +58,6 @@ public:
PlayingSoundHandle _talkChannelHandle; // Handle of mixer channel actor is talking on
bool _soundsPaused;
byte _sfxMode;
-
- Bundle *_bundle; // FIXME: should be protected but is used by ScummEngine::askForDisk
public:
Sound(ScummEngine *parent);
@@ -105,14 +80,6 @@ public:
void setupSound();
void pauseSounds(bool pause);
- void playBundleMusic(const char *song);
- void pauseBundleMusic(bool state);
- void bundleMusicHandler(ScummEngine *scumm);
- void stopBundleMusic();
- void playBundleSound(char *sound, PlayingSoundHandle *handle);
-
- uint32 decode12BitsSample(byte *src, byte **dst, uint32 size, bool stereo);
-
void startCDTimer();
void stopCDTimer();
diff --git a/scumm/string.cpp b/scumm/string.cpp
index fc55dda3d5..f9f01f8f51 100644
--- a/scumm/string.cpp
+++ b/scumm/string.cpp
@@ -25,6 +25,7 @@
#include "scumm/actor.h"
#include "scumm/charset.h"
#include "scumm/dialogs.h"
+#include "scumm/imuse_digi.h"
#include "scumm/verbs.h"
#include "scumm/sound.h"
@@ -899,7 +900,7 @@ const byte *ScummEngine::translateTextAndPlaySpeech(const byte *ptr) {
pointer[j] = 0;
// Play speech
- _sound->playBundleSound(pointer, &_sound->_talkChannelHandle);
+ _imuseDigital->playBundleSound(pointer, &_sound->_talkChannelHandle);
ptr = _transText;
}