diff options
author | Filippos Karapetis | 2008-12-01 20:35:36 +0000 |
---|---|---|
committer | Filippos Karapetis | 2008-12-01 20:35:36 +0000 |
commit | af945ac7881ae7e414f004bd0e99e8c3b5d76be9 (patch) | |
tree | 72e9c6fd43406e2021973b4f163ab4faa10143fb /engines/tinsel/sound.cpp | |
parent | f10f151ff742801e12534bb052bd89419bf906cb (diff) | |
download | scummvm-rg350-af945ac7881ae7e414f004bd0e99e8c3b5d76be9.tar.gz scummvm-rg350-af945ac7881ae7e414f004bd0e99e8c3b5d76be9.tar.bz2 scummvm-rg350-af945ac7881ae7e414f004bd0e99e8c3b5d76be9.zip |
Merged the tinsel 2 engine with tinsel 1. Both Discworld 1 and Discworld 2 should be completable
svn-id: r35196
Diffstat (limited to 'engines/tinsel/sound.cpp')
-rw-r--r-- | engines/tinsel/sound.cpp | 290 |
1 files changed, 272 insertions, 18 deletions
diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp index e37c80ec61..9d1996ca01 100644 --- a/engines/tinsel/sound.cpp +++ b/engines/tinsel/sound.cpp @@ -31,6 +31,8 @@ #include "tinsel/music.h" #include "tinsel/strres.h" #include "tinsel/tinsel.h" +#include "tinsel/sysvar.h" +#include "tinsel/background.h" #include "common/endian.h" #include "common/file.h" @@ -38,14 +40,20 @@ #include "sound/mixer.h" #include "sound/audiocd.h" +#include "sound/adpcm.h" namespace Tinsel { +extern LANGUAGE sampleLanguage; + //--------------------------- General data ---------------------------------- SoundManager::SoundManager(TinselEngine *vm) : //_vm(vm), // TODO: Enable this once global _vm var is gone _sampleIndex(0), _sampleIndexLen(0) { + + for (int i = 0; i < kNumChannels; i++) + _channels[i].sampleNum = _channels[i].subSample = -1; } SoundManager::~SoundManager() { @@ -67,24 +75,29 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound if (!_vm->_mixer->isReady()) return false; + Channel &curChan = _channels[kChannelTinsel1]; + // stop any currently playing sample - _vm->_mixer->stopHandle(_handle); + _vm->_mixer->stopHandle(curChan.handle); // make sure id is in range assert(id > 0 && id < _sampleIndexLen); + curChan.sampleNum = id; + curChan.subSample = 0; + // get file offset for this sample - int32 dwSampleIndex = _sampleIndex[id]; + uint32 dwSampleIndex = _sampleIndex[id]; // move to correct position in the sample file _sampleStream.seek(dwSampleIndex); - if (_sampleStream.ioFailed() || _sampleStream.pos() != dwSampleIndex) - error("File %s is corrupt", SAMPLE_FILE); + if (_sampleStream.ioFailed() || (uint32)_sampleStream.pos() != dwSampleIndex) + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); // read the length of the sample uint32 sampleLen = _sampleStream.readUint32LE(); if (_sampleStream.ioFailed()) - error("File %s is corrupt", SAMPLE_FILE); + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); // allocate a buffer void *sampleBuf = malloc(sampleLen); @@ -92,7 +105,7 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound // read all of the sample if (_sampleStream.read(sampleBuf, sampleLen) != sampleLen) - error("File %s is corrupt", SAMPLE_FILE); + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); // FIXME: Should set this in a different place ;) _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volSound); @@ -101,15 +114,211 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound // play it - _vm->_mixer->playRaw(type, &_handle, sampleBuf, sampleLen, 22050, + _vm->_mixer->playRaw(type, &curChan.handle, sampleBuf, sampleLen, 22050, Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED); if (handle) - *handle = _handle; + *handle = curChan.handle; return true; } +bool SoundManager::playSample(int id, int sub, bool bLooped, int x, int y, int priority, + Audio::Mixer::SoundType type, Audio::SoundHandle *handle) { + + // Floppy version has no sample file + if (_vm->getFeatures() & GF_FLOPPY) + return false; + + // no sample driver? + if (!_vm->_mixer->isReady()) + return false; + + Channel *curChan; + + uint8 sndVol = 255; + + // Sample on screen? + if (!offscreenChecks(x, y)) + return false; + + // If that sample is already playing, stop it + stopSpecSample(id, sub); + + if (type == Audio::Mixer::kSpeechSoundType) { + curChan = &_channels[kChannelTalk]; + } else if (type == Audio::Mixer::kSFXSoundType) { + uint32 oldestTime = g_system->getMillis(); + int oldestChan = kChannelSFX; + + int chan; + for (chan = kChannelSFX; chan < kNumChannels; chan++) { + if (!_vm->_mixer->isSoundHandleActive(_channels[chan].handle)) + break; + + if ((_channels[chan].lastStart < oldestTime) && + (_channels[chan].priority <= priority)) { + + oldestTime = _channels[chan].lastStart; + oldestChan = chan; + } + } + + if (chan == kNumChannels) { + if (_channels[oldestChan].priority > priority) { + warning("playSample: No free channel"); + return false; + } + + chan = oldestChan; + } + + if (_vm->_pcmMusic->isDimmed() && SysVar(SYS_SceneFxDimFactor)) + sndVol = 255 - 255/SysVar(SYS_SceneFxDimFactor); + + curChan = &_channels[chan]; + } else { + warning("playSample: Unknown SoundType"); + return false; + } + + // stop any currently playing sample + _vm->_mixer->stopHandle(curChan->handle); + + // make sure id is in range + assert(id > 0 && id < _sampleIndexLen); + + // get file offset for this sample + uint32 dwSampleIndex = _sampleIndex[id]; + + if (dwSampleIndex == 0) { + warning("Tinsel2 playSample, non-existant sample %d", id); + return false; + } + + // move to correct position in the sample file + _sampleStream.seek(dwSampleIndex); + if (_sampleStream.ioFailed() || (uint32)_sampleStream.pos() != dwSampleIndex) + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); + + // read the length of the sample + uint32 sampleLen = _sampleStream.readUint32LE(); + if (_sampleStream.ioFailed()) + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); + + if (sampleLen & 0x80000000) { + // Has sub samples + + int32 numSubs = sampleLen & ~0x80000000; + + assert(sub >= 0 && sub < numSubs); + + // Skipping + for (int32 i = 0; i < sub; i++) { + sampleLen = _sampleStream.readUint32LE(); + _sampleStream.skip(sampleLen); + if (_sampleStream.ioFailed()) + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); + } + sampleLen = _sampleStream.readUint32LE(); + if (_sampleStream.ioFailed()) + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); + } + + debugC(DEBUG_DETAILED, kTinselDebugSound, "Playing sound %d.%d, %d bytes at %d (pan %d)", id, sub, sampleLen, + _sampleStream.pos(), getPan(x)); + + // allocate a buffer + byte *sampleBuf = (byte *) malloc(sampleLen); + assert(sampleBuf); + + // read all of the sample + if (_sampleStream.read(sampleBuf, sampleLen) != sampleLen) + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); + + Common::MemoryReadStream *sampleStream = + new Common::MemoryReadStream(sampleBuf, sampleLen, true); + Audio::AudioStream *_stream = + makeADPCMStream(sampleStream, true, sampleLen, Audio::kADPCMTinsel6, 22050, 1, 24); + + // FIXME: Should set this in a different place ;) + _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volSound); + //_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic); + _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volVoice); + + curChan->sampleNum = id; + curChan->subSample = sub; + curChan->looped = bLooped; + curChan->x = x; + curChan->y = y; + curChan->priority = priority; + curChan->lastStart = g_system->getMillis(); + // /---Compression----\ Milis BytesPerSecond + curChan->timeDuration = (((sampleLen * 64) / 25) * 1000) / (22050 * 2); + + // Play it + _vm->_mixer->playInputStream(type, &curChan->handle, _stream); + _vm->_mixer->setChannelVolume(curChan->handle, sndVol); + _vm->_mixer->setChannelBalance(curChan->handle, getPan(x)); + + if (handle) + *handle = curChan->handle; + + return true; +} + +/** + * Returns FALSE if sample doesn't need playing + */ +bool SoundManager::offscreenChecks(int x, int &y) +{ + // No action if no x specification + if (x == -1) + return true; + + // convert x to offset from screen centre + x -= PlayfieldGetCentreX(FIELD_WORLD); + + if (x < -SCREEN_WIDTH || x > SCREEN_WIDTH) { + // A long way offscreen, ignore it + return false; + } else if (x < -SCREEN_WIDTH/2 || x > SCREEN_WIDTH/2) { + // Off-screen, attennuate it + + y = (y > 0) ? (y / 2) : 50; + + return true; + } else + return true; +} + +int8 SoundManager::getPan(int x) { + + if (x == -1) + return 0; + + x -= PlayfieldGetCentreX(FIELD_WORLD); + + if (x == 0) + return 0; + + if (x < 0) { + if (x < (-SCREEN_WIDTH / 2)) + return -127; + + x = (-x * 127) / (SCREEN_WIDTH / 2); + + return 0 - x; + } + + if (x > (SCREEN_WIDTH / 2)) + return 127; + + x = (x * 127) / (SCREEN_WIDTH / 2); + + return x; +} + /** * Returns TRUE if there is a sample for the specified sample identifier. * @param id Identifier of sample to be checked @@ -131,8 +340,16 @@ bool SoundManager::sampleExists(int id) { /** * Returns true if a sample is currently playing. */ -bool SoundManager::sampleIsPlaying(void) { - return _vm->_mixer->isSoundHandleActive(_handle); +bool SoundManager::sampleIsPlaying(int id) { + if (!TinselV2) + return _vm->_mixer->isSoundHandleActive(_channels[kChannelTinsel1].handle); + + for (int i = 0; i < kNumChannels; i++) + if (_channels[i].sampleNum == id) + if (_vm->_mixer->isSoundHandleActive(_channels[i].handle)) + return true; + + return false; } /** @@ -140,7 +357,37 @@ bool SoundManager::sampleIsPlaying(void) { */ void SoundManager::stopAllSamples(void) { // stop currently playing sample - _vm->_mixer->stopHandle(_handle); + + if (!TinselV2) { + _vm->_mixer->stopHandle(_channels[kChannelTinsel1].handle); + return; + } + + for (int i = 0; i < kNumChannels; i++) + _vm->_mixer->stopHandle(_channels[i].handle); +} + +void SoundManager::stopSpecSample(int id, int sub) { + debugC(DEBUG_DETAILED, kTinselDebugSound, "stopSpecSample(%d, %d)", id, sub); + + if (!TinselV2) { + if (_channels[kChannelTinsel1].sampleNum == id) + _vm->_mixer->stopHandle(_channels[kChannelTinsel1].handle); + return; + } + + for (int i = kChannelTalk; i < kNumChannels; i++) { + if ((_channels[i].sampleNum == id) && (_channels[i].subSample == sub)) + _vm->_mixer->stopHandle(_channels[i].handle); + } +} + +void SoundManager::setSFXVolumes(uint8 volume) { + if (!TinselV2) + return; + + for (int i = kChannelSFX; i < kNumChannels; i++) + _vm->_mixer->setChannelVolume(_channels[i].handle, volume); } /** @@ -158,7 +405,7 @@ void SoundManager::openSampleFiles(void) { return; // open sample index file in binary mode - if (f.open(SAMPLE_INDEX)) { + if (f.open(_vm->getSampleIndex(sampleLanguage))) { // get length of index file f.seek(0, SEEK_END); // move to end of file _sampleIndexLen = f.pos(); // get file pointer @@ -166,7 +413,7 @@ void SoundManager::openSampleFiles(void) { if (_sampleIndex == NULL) { // allocate a buffer for the indices - _sampleIndex = (int32 *)malloc(_sampleIndexLen); + _sampleIndex = (uint32 *)malloc(_sampleIndexLen); // make sure memory allocated if (_sampleIndex == NULL) { @@ -179,7 +426,7 @@ void SoundManager::openSampleFiles(void) { // load data if (f.read(_sampleIndex, _sampleIndexLen) != (uint32)_sampleIndexLen) // file must be corrupt if we get to here - error("File %s is corrupt", SAMPLE_FILE); + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); #ifdef SCUMM_BIG_ENDIAN // Convert all ids from LE to native format @@ -194,18 +441,25 @@ void SoundManager::openSampleFiles(void) { // convert file size to size in DWORDs _sampleIndexLen /= sizeof(uint32); } else - error("Cannot find file %s", SAMPLE_INDEX); + error(CANNOT_FIND_FILE, _vm->getSampleIndex(sampleLanguage)); // open sample file in binary mode - if (!_sampleStream.open(SAMPLE_FILE)) - error("Cannot find file %s", SAMPLE_FILE); + if (!_sampleStream.open(_vm->getSampleFile(sampleLanguage))) + error(CANNOT_FIND_FILE, _vm->getSampleFile(sampleLanguage)); /* // gen length of the largest sample sampleBuffer.size = _sampleStream.readUint32LE(); if (_sampleStream.ioFailed()) - error("File %s is corrupt", SAMPLE_FILE); + error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); */ } +void SoundManager::closeSampleStream(void) { + _sampleStream.close(); + free(_sampleIndex); + _sampleIndex = 0; + _sampleIndexLen = 0; +} + } // end of namespace Tinsel |