diff options
Diffstat (limited to 'scumm')
-rw-r--r-- | scumm/imuse_digi.cpp | 224 | ||||
-rw-r--r-- | scumm/imuse_digi.h | 11 | ||||
-rw-r--r-- | scumm/script_v8.cpp | 7 | ||||
-rw-r--r-- | scumm/sound.cpp | 95 | ||||
-rw-r--r-- | scumm/string.cpp | 7 |
5 files changed, 141 insertions, 203 deletions
diff --git a/scumm/imuse_digi.cpp b/scumm/imuse_digi.cpp index 8db1fb3dd4..53641531a4 100644 --- a/scumm/imuse_digi.cpp +++ b/scumm/imuse_digi.cpp @@ -634,58 +634,6 @@ static const imuse_ft_music_table _ftSeqMusicTable[] = { }; #endif -static byte *readCreativeVocFile(byte *ptr, int32 &size, int &rate) { - assert(strncmp((char *)ptr, "Creative Voice File\x1A", 20) == 0); - int32 offset = READ_LE_UINT16(ptr + 20); - int16 version = READ_LE_UINT16(ptr + 22); - int16 code = READ_LE_UINT16(ptr + 24); - assert(version == 0x010A || version == 0x0114); - assert(code == ~version + 0x1234); - bool quit = 0; - byte *ret_sound = 0; size = 0; - int loops = 0; - while (!quit) { - int len = READ_LE_UINT32(ptr + offset); - offset += 4; - code = len & 0xFF; - len >>= 8; - switch(code) { - case 0: quit = 1; break; - case 1: { - int time_constant = ptr[offset++]; - int packing = ptr[offset++]; - len -= 2; - rate = getSampleRateFromVOCRate(time_constant); - debug(9, "VOC Data Bloc : %d, %d, %d", rate, packing, len); - if (packing == 0) { - if (size) { - ret_sound = (byte *)realloc(ret_sound, size + len); - } else { - ret_sound = (byte *)malloc(len); - } - memcpy(ret_sound + size, ptr + offset, len); - size += len; - } else { - warning("VOC file packing %d unsupported", packing); - } - } break; - case 6: // begin of loop - loops = len + 1; - break; - case 7: // end of loop - break; - default: - warning("Invalid code in VOC file : %d", code); - quit = 1; - break; - } - // FIXME some FT samples (ex. 362) has bad length, 2 bytes too short - offset += len; - } - debug(9, "VOC Data Size : %d", size); - return ret_sound; -} - static uint32 decode12BitsSample(byte *src, byte **dst, uint32 size, bool stereo) { uint32 loop_size = size / 3; uint32 s_size = loop_size * 4; @@ -722,6 +670,12 @@ IMuseDigital::IMuseDigital(ScummEngine *scumm) : _scumm(scumm) { _pause = false; + _voiceVocData = NULL; + _voiceVocSize = 0; + _voiceVocRate = 0; + + _voiceBundleData = NULL; + _nameBundleMusic = ""; _musicBundleBufFinal = NULL; _musicBundleBufOutput = NULL; @@ -802,17 +756,36 @@ void IMuseDigital::callback() { } } +void IMuseDigital::setVocVoice(byte *src, int32 size, int rate) { + _voiceVocData = src; + _voiceVocSize = size; + _voiceVocRate = rate; +} + +void IMuseDigital::setBundleVoice(byte *src) { + _voiceBundleData = src; +} + void IMuseDigital::startSound(int sound) { debug(5, "IMuseDigital::startSound(%d)", sound); int l, r; for (l = 0; l < MAX_DIGITAL_CHANNELS; l++) { if (!_channel[l].used && !_channel[l].handle.isActive()) { - byte *ptr = _scumm->getResourceAddress(rtSound, sound); - byte *s_ptr = ptr; - if (ptr == NULL) { - warning("IMuseDigital::startSound(%d) NULL resource pointer", sound); - return; + byte *ptr, *s_ptr; + if ((sound == 10000) && (_voiceBundleData)) { + s_ptr = ptr = _voiceBundleData; + } else if ((sound == 10000) && (_voiceVocData)) { + // + } else if (sound != 10000) { + ptr = _scumm->getResourceAddress(rtSound, sound); + s_ptr = ptr; + if (ptr == NULL) { + warning("IMuseDigital::startSound(%d) NULL resource pointer", sound); + return; + } + } else { + error("IMuseDigital::startSound() unknown condition"); } _channel[l].pan = 0; _channel[l].vol = 127 * 1000; @@ -832,8 +805,22 @@ void IMuseDigital::startSound(int sound) { int32 size = 0; int t; - if (READ_UINT32(ptr) == MKID('Crea')) { - byte *t_ptr= readCreativeVocFile(ptr, size, _channel[l].freq); + if ((sound == 10000) && (_voiceVocData)) { + _channel[l].mixerSize = _voiceVocRate * 2; + _channel[l].size = _voiceVocSize * 2; + _channel[l].bits = 8; + _channel[l].channels = 2; + _channel[l].mixerFlags = SoundMixer::FLAG_STEREO | SoundMixer::FLAG_REVERSE_STEREO | SoundMixer::FLAG_UNSIGNED; + _channel[l].data = (byte *)malloc(_channel[l].size); + + for (t = 0; t < _channel[l].size / 2; t++) { + *(_channel[l].data + t * 2 + 0) = *(_voiceVocData + t); + *(_channel[l].data + t * 2 + 1) = *(_voiceVocData + t); + } + + _voiceVocRate = NULL; + } else if (READ_UINT32(ptr) == MKID('Crea')) { + byte *t_ptr= readCreativeVoc(ptr, size, _channel[l].freq); _channel[l].mixerSize = _channel[l].freq * 2; _channel[l].size = size * 2; _channel[l].bits = 8; @@ -897,6 +884,9 @@ void IMuseDigital::startSound(int sound) { _channel[l].jump[_channel[l].numJumps].fadeDelay = READ_BE_UINT32(ptr); ptr += 4; _channel[l].numJumps++; break; + 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; @@ -907,6 +897,16 @@ void IMuseDigital::startSound(int sound) { break; } + if ((sound == 10000) && (_voiceBundleData)) { + if (_scumm->_actorToPrintStrFor != 0xFF && _scumm->_actorToPrintStrFor != 0) { + Actor *a = _scumm->derefActor(_scumm->_actorToPrintStrFor, "playBundleSound"); + _channel[l].freq = (_channel[l].freq * a->talkFrequency) / 256; + + // Adjust to fit the mixer's notion of panning. + _channel[l].pan = (a->talkPan != 64) ? 2 * a->talkPan - 127 : 0; + } + } + uint32 header_size = ptr - s_ptr; _channel[l].offsetStop -= header_size; @@ -938,6 +938,26 @@ void IMuseDigital::startSound(int sound) { _channel[l].mixerSize *= 2; _channel[l].mixerFlags |= SoundMixer::FLAG_16BITS; _channel[l].size = decode12BitsSample(ptr, &_channel[l].data, size, (_channel[l].channels == 2) ? false : true); + } else if (_channel[l].bits == 16) { + _channel[l].mixerSize *= 2; + _channel[l].mixerFlags |= SoundMixer::FLAG_16BITS; + + // 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; + + if (_channel[l].channels == 1) { + size *= 2; + _channel[l].channels = 2; + _channel[l].data = (byte *)malloc(size); + for (t = 0; t < size / 4; t++) { + *(_channel[l].data + t * 4 + 0) = *(ptr + t * 2 + 0); + *(_channel[l].data + t * 4 + 1) = *(ptr + t * 2 + 1); + *(_channel[l].data + t * 4 + 2) = *(ptr + t * 2 + 0); + *(_channel[l].data + t * 4 + 3) = *(ptr + t * 2 + 1); + } + } + _channel[l].size = size; } else if (_channel[l].bits == 8) { _channel[l].mixerFlags |= SoundMixer::FLAG_UNSIGNED; if (_channel[l].channels == 1) { @@ -1408,9 +1428,8 @@ void IMuseDigital::bundleMusicHandler() { free(buffer); } -void IMuseDigital::playBundleSound(const char *sound, PlayingSoundHandle *handle) { +void IMuseDigital::playBundleSound(const char *sound) { byte *ptr = 0, *orig_ptr = 0; - byte *final; bool result; if (!_scumm->_mixer->isReady()) @@ -1427,7 +1446,7 @@ void IMuseDigital::playBundleSound(const char *sound, PlayingSoundHandle *handle result = _bundle->openVoiceFile(voxfile, _scumm->getGameDataPath()); - if (result == false) + if (result == false) result = _bundle->openVoiceFile("voice.bun", _scumm->getGameDataPath()); _voiceDisk = (byte)_scumm->VAR(_scumm->VAR_CURRENTDISK); } @@ -1439,89 +1458,22 @@ void IMuseDigital::playBundleSound(const char *sound, PlayingSoundHandle *handle if (!result) return; - int32 rate = 22050, pan = 0, channels = 0, 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); + _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; + _bundle->decompressVoiceSampleByName(sound, &ptr); } - 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 '%s'", tag2str(tag)); - } - } - - if (size < 0) { - warning("Decompression sound failed (no size field)"); - goto bail; + if (ptr) { + stopSound(10000); + setBundleVoice(ptr); + startSound(10000); + free(ptr); } - - 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. - pan = (a->talkPan != 64) ? 2 * a->talkPan - 127 : 0; - } - - // Stop any sound currently playing on the given handle - if (handle) - _scumm->_mixer->stopHandle(*handle); - - assert(channels == 1); - 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 diff --git a/scumm/imuse_digi.h b/scumm/imuse_digi.h index 913f1e72e7..eb7ade49d2 100644 --- a/scumm/imuse_digi.h +++ b/scumm/imuse_digi.h @@ -128,11 +128,18 @@ private: public: int32 _bundleSongPosInMs; Bundle *_bundle; // FIXME: should be protected but is used by ScummEngine::askForDisk + byte *_voiceVocData; + int32 _voiceVocSize; + int _voiceVocRate; + + byte *_voiceBundleData; void pauseBundleMusic(bool state); void stopBundleMusic(); - void playBundleSound(const char *sound, PlayingSoundHandle *handle); - + void playBundleSound(const char *sound); + void setVocVoice(byte *src, int32 size, int rate); + void setBundleVoice(byte *src); + public: IMuseDigital(ScummEngine *scumm); ~IMuseDigital(); diff --git a/scumm/script_v8.cpp b/scumm/script_v8.cpp index 6d4afc2bff..b4675ce533 100644 --- a/scumm/script_v8.cpp +++ b/scumm/script_v8.cpp @@ -1078,9 +1078,10 @@ void ScummEngine_v8::o8_actorOps() { // on the current talk channel handle. (If the handle is 0, // setChannelPan() won't do anything.) - if (_actorToPrintStrFor == a->number) - _mixer->setChannelPan(_sound->_talkChannelHandle, - (a->talkPan != 64) ? 2 * a->talkPan - 127 : 0); + if (_actorToPrintStrFor == a->number) { + if (_sound->isSoundRunning(10000)) + _imuseDigital->parseScriptCmds(12, 0x700, 10000, a->talkPan, 0, 0, 0, 0); + } break; default: diff --git a/scumm/sound.cpp b/scumm/sound.cpp index 0590a2696f..5523635069 100644 --- a/scumm/sound.cpp +++ b/scumm/sound.cpp @@ -39,11 +39,6 @@ namespace Scumm { -enum { - SOUND_HEADER_SIZE = 26, - SOUND_HEADER_BIG_SIZE = 26 + 8 -}; - struct MP3OffsetTable { /* Compressed Sound (.SO3) */ int org_offset; int new_offset; @@ -411,7 +406,11 @@ void Sound::processSfxQueues() { if ((_sfxMode & 2) && _scumm->VAR(_scumm->VAR_TALK_ACTOR)) { act = _scumm->VAR(_scumm->VAR_TALK_ACTOR); - finished = !_talkChannelHandle.isActive(); + if (_scumm->_imuseDigital) { + finished = !isSoundRunning(10000); + } else { + finished = !_talkChannelHandle.isActive(); + } if (act != 0 && (uint) act < 0x80 && !_scumm->_string[0].no_talk_anim) { a = _scumm->derefActor(act, "processSfxQueues"); @@ -486,14 +485,13 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, PlayingSoundHandle warning("startTalkSound: dig demo: voc file not found"); return; } - } else { if (!_sfxFile->isOpen()) { warning("startTalkSound: SFX file is not open"); return; } - + // FIXME hack until more is known // the size of the data after the sample isn't known // 64 is just a guess @@ -506,7 +504,7 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, PlayingSoundHandle _scumm->_mixer->playRaw(handle, sound, b - 64, 11025, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE); return; } - + // Some games frequently assume that starting one sound effect will // automatically stop any other that may be playing at that time. So // that is what we do here, but we make an exception for speech. @@ -515,24 +513,24 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, PlayingSoundHandle // // HACK: Checking for script 99 in Sam & Max is to keep Conroy's song // from being interrupted. - + if (mode == 1 && (_scumm->_gameId == GID_TENTACLE || (_scumm->_gameId == GID_SAMNMAX && !_scumm->isScriptRunning(99)))) { id = 777777; _scumm->_mixer->stopID(id); } - + if (b > 8) { num = (b - 8) >> 1; } - + if (offset_table != NULL) { MP3OffsetTable *result = NULL, key; key.org_offset = offset; result = (MP3OffsetTable *)bsearch(&key, offset_table, num_sound_effects, sizeof(MP3OffsetTable), compareMP3OffsetTable); - + if (result == NULL) { warning("startTalkSound: did not find sound at offset %d !", offset); return; @@ -548,10 +546,10 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, PlayingSoundHandle offset += 8; size = -1; } - + _sfxFile->seek(offset, SEEK_SET); - - assert(num+1 < (int)ARRAYSIZE(_mouthSyncTimes)); + + assert(num + 1 < (int)ARRAYSIZE(_mouthSyncTimes)); for (i = 0; i < num; i++) _mouthSyncTimes[i] = _sfxFile->readUint16BE(); @@ -566,7 +564,11 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, PlayingSoundHandle void Sound::stopTalkSound() { if (_sfxMode & 2) { - _scumm->_mixer->stopHandle(_talkChannelHandle); + if (_scumm->_imuseDigital) { + _scumm->_imuseDigital->stopSound(10000); + } else { + _scumm->_mixer->stopHandle(_talkChannelHandle); + } _sfxMode &= ~2; } } @@ -797,10 +799,6 @@ void Sound::pauseSounds(bool pause) { } void Sound::startSfxSound(File *file, int file_size, PlayingSoundHandle *handle, int id) { - char ident[8]; - uint size = 0; - int rate, comp; - byte *data; if (_soundsPaused || !_scumm->_mixer->isReady()) return; @@ -818,47 +816,17 @@ void Sound::startSfxSound(File *file, int file_size, PlayingSoundHandle *handle, return; } - if (file->read(ident, 8) != 8) - goto invalid; + int32 size; + int rate; + byte *data = loadVocSample(_sfxFile, size, rate); - if (!memcmp(ident, "VTLK", 4)) { - file->seek(SOUND_HEADER_BIG_SIZE - 8, SEEK_CUR); - } else if (!memcmp(ident, "Creative", 8)) { - file->seek(SOUND_HEADER_SIZE - 8, SEEK_CUR); + if (_scumm->_imuseDigital) { + _scumm->_imuseDigital->setVocVoice(data, size, rate); + _scumm->_imuseDigital->startSound(10000); + free(data); } else { - invalid:; - warning("startSfxSound: invalid header"); - return; - } - - VocBlockHeader voc_block_hdr; - - file->read(&voc_block_hdr, sizeof(voc_block_hdr)); - if (voc_block_hdr.blocktype != 1) { - warning("startSfxSound: Expecting block_type == 1, got %d", voc_block_hdr.blocktype); - return; - } - - size = voc_block_hdr.size[0] + (voc_block_hdr.size[1] << 8) + (voc_block_hdr.size[2] << 16) - 2; - rate = getSampleRateFromVOCRate(voc_block_hdr.sr); - comp = voc_block_hdr.pack; - - if (comp != 0) { - warning("startSfxSound: Unsupported compression type %d", comp); - return; - } - - data = (byte *)malloc(size); - if (data == NULL) { - error("startSfxSound: out of memory"); + _scumm->_mixer->playRaw(handle, data, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED, id); } - - if (file->read(data, size) != size) { - /* no need to free the memory since error will shut down */ - error("startSfxSound: cannot read %d bytes", size); - } - - _scumm->_mixer->playRaw(handle, data, size, rate, SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_UNSIGNED, id); } File *Sound::openSfxFile() { @@ -870,6 +838,15 @@ File *Sound::openSfxFile() { * same directory */ offset_table = NULL; + // for now until better streaming will be, ft voice can't not be compressed + if (_scumm->_imuseDigital) { + sprintf(buf, "%s.sou", _scumm->getGameName()); + if (!file->open(buf, _scumm->getGameDataPath())) { + file->open("monster.sou", _scumm->getGameDataPath()); + } + return file; + } + #ifdef USE_MAD sprintf(buf, "%s.so3", _scumm->getGameName()); if (!file->open(buf, _scumm->getGameDataPath())) { diff --git a/scumm/string.cpp b/scumm/string.cpp index 69d5ed5e6c..1a15a48255 100644 --- a/scumm/string.cpp +++ b/scumm/string.cpp @@ -163,9 +163,10 @@ void ScummEngine::CHARSET_1() { if (_talkDelay) return; - if ((_gameId == GID_CMI || _gameId == GID_DIG) && _sound->_talkChannelHandle.isActive()) { + if ((_gameId == GID_CMI || _gameId == GID_DIG) && (_imuseDigital) + && _sound->isSoundRunning(10000)) { // Keep the 'speech' flag in _sound->_sfxMode set as long as the - // _talkChannelHandle is valid. + // sound 10000 is playing. _sound->_sfxMode |= 2; } @@ -900,7 +901,7 @@ const byte *ScummEngine::translateTextAndPlaySpeech(const byte *ptr) { pointer[j] = 0; // Play speech - _imuseDigital->playBundleSound(pointer, &_sound->_talkChannelHandle); + _imuseDigital->playBundleSound(pointer); ptr = _transText; } |