diff options
Diffstat (limited to 'engines/tsage/sound.cpp')
-rw-r--r-- | engines/tsage/sound.cpp | 313 |
1 files changed, 153 insertions, 160 deletions
diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp index e26b3d1544..0b77628801 100644 --- a/engines/tsage/sound.cpp +++ b/engines/tsage/sound.cpp @@ -20,6 +20,7 @@ * */ +#include "audio/decoders/raw.h" #include "common/config-manager.h" #include "tsage/core.h" #include "tsage/globals.h" @@ -27,7 +28,7 @@ #include "tsage/graphics.h" #include "tsage/tsage.h" -namespace tSage { +namespace TsAGE { static SoundManager *_soundManager = NULL; @@ -53,6 +54,7 @@ SoundManager::SoundManager() { SoundManager::~SoundManager() { if (__sndmgrReady) { Common::StackLock slock(_serverDisabledMutex); + _vm->_mixer->stopAll(); for (Common::List<Sound *>::iterator i = _soundList.begin(); i != _soundList.end(); ) { Sound *s = *i; @@ -66,7 +68,15 @@ SoundManager::~SoundManager() { } _sfTerminate(); - g_system->getTimerManager()->removeTimerProc(_sfUpdateCallback); +// g_system->getTimerManager()->removeTimerProc(_sfUpdateCallback); + } + + // Free any allocated voice type structures + for (int idx = 0; idx < SOUND_ARR_SIZE; ++idx) { + if (sfManager()._voiceTypeStructPtrs[idx]) { + delete sfManager()._voiceTypeStructPtrs[idx]; + sfManager()._voiceTypeStructPtrs[idx] = NULL; + } } _soundManager = NULL; @@ -78,9 +88,12 @@ void SoundManager::postInit() { _saver->addLoadNotifier(&SoundManager::loadNotifier); _saver->addListener(this); - // Install a timer for handling sound manager updates at 60Hz - g_system->getTimerManager()->installTimerProc(_sfUpdateCallback, 1000000 / GAME_FRAME_RATE, NULL); +// I originally separated the sound manager update method into a separate thread, since +// it handles updates for both music and Fx. However, since Adlib updates also get done in a +// thread, and doesn't get too far ahead, I've left it to the AdlibSoundDriver class to +// call the update method, rather than having it be called separately +// g_system->getTimerManager()->installTimerProc(_sfUpdateCallback, 1000000 / SOUND_FREQUENCY, NULL, "tsageSoundUpdate"); __sndmgrReady = true; } } @@ -155,9 +168,7 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) { void SoundManager::installConfigDrivers() { installDriver(ADLIB_DRIVER_NUM); -#ifdef DEBUG installDriver(SBLASTER_DRIVER_NUM); -#endif } Common::List<SoundDriverEntry> &SoundManager::getDriverList(bool detectFlag) { @@ -226,7 +237,7 @@ SoundDriver *SoundManager::instantiateDriver(int driverNum) { case ADLIB_DRIVER_NUM: return new AdlibSoundDriver(); case SBLASTER_DRIVER_NUM: - return new AdlibFxSoundDriver(); + return new SoundBlasterDriver(); default: error("Unknown sound driver - %d", driverNum); } @@ -357,9 +368,6 @@ void SoundManager::rethinkVoiceTypes() { } void SoundManager::_sfSoundServer() { - Common::StackLock slock1(sfManager()._serverDisabledMutex); - Common::StackLock slock2(sfManager()._serverSuspendedMutex); - if (sfManager()._needToRethink) { _sfRethinkVoiceTypes(); sfManager()._needToRethink = false; @@ -451,6 +459,22 @@ void SoundManager::_sfProcessFading() { } } +bool SoundManager::isFading() { + Common::StackLock slock(sfManager()._serverSuspendedMutex); + + // Loop through any active sounds to see if any are being actively faded + Common::List<Sound *>::iterator i = sfManager()._playList.begin(); + while (i != sfManager()._playList.end()) { + Sound *s = *i; + ++i; + + if (s->_fadeDest != -1) + return true; + } + + return false; +} + void SoundManager::_sfUpdateVoiceStructs() { for (int voiceIndex = 0; voiceIndex < SOUND_ARR_SIZE; ++voiceIndex) { VoiceTypeStruct *vs = sfManager()._voiceTypeStructPtrs[voiceIndex]; @@ -1341,7 +1365,7 @@ bool SoundManager::_sfInstallDriver(SoundDriver *driver) { sfManager()._installedDrivers.push_back(driver); driver->_groupOffset = driver->getGroupData(); - driver->_groupMask = READ_LE_UINT32(driver->_groupOffset); + driver->_groupMask = driver->_groupOffset->groupMask; _sfExtractGroupMask(); _sfRethinkSoundDrivers(); @@ -1967,9 +1991,9 @@ void Sound::_soServiceTrackType0(int trackIndex, const byte *channelData) { if (channelNum != -1) { if (voiceType != VOICETYPE_0) { if (chFlags & 0x10) - _soProc42(vtStruct, channelNum, chVoiceType, v); + _soPlaySound2(vtStruct, channelData, channelNum, chVoiceType, v); else - _soProc32(vtStruct, channelNum, chVoiceType, v, b); + _soPlaySound(vtStruct, channelData, channelNum, chVoiceType, v, b); } else if (voiceNum != -1) { assert(driver); driver->proc20(voiceNum, chVoiceType); @@ -2137,7 +2161,7 @@ void Sound::_soUpdateDamper(VoiceTypeStruct *voiceType, int channelNum, VoiceTyp } } -void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0, int v1) { +void Sound::_soPlaySound(VoiceTypeStruct *vtStruct, const byte *channelData, int channelNum, VoiceType voiceType, int v0, int v1) { int entryIndex = _soFindSound(vtStruct, channelNum); if (entryIndex != -1) { SoundDriver *driver = vtStruct->_entries[entryIndex]._driver; @@ -2147,11 +2171,11 @@ void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice vtStruct->_entries[entryIndex]._type1._field4 = v0; vtStruct->_entries[entryIndex]._type1._field5 = 0; - driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum], v0, v1); + driver->playSound(channelData, 0, _chProgram[channelNum], vtStruct->_entries[entryIndex]._voiceNum, v0, v1); } } -void Sound::_soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0) { +void Sound::_soPlaySound2(VoiceTypeStruct *vtStruct, const byte *channelData, int channelNum, VoiceType voiceType, int v0) { for (int trackCtr = 0; trackCtr < _trackInfo._numTracks; ++trackCtr) { const byte *instrument = _channelData[trackCtr]; if ((*(instrument + 13) == v0) && (*instrument == 1)) { @@ -2160,13 +2184,14 @@ void Sound::_soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice if (entryIndex != -1) { SoundDriver *driver = vtStruct->_entries[entryIndex]._driver; assert(driver); + byte *trackData = _channelData[trackCtr]; vtStruct->_entries[entryIndex]._type1._field6 = 0; vtStruct->_entries[entryIndex]._type1._field4 = v0; vtStruct->_entries[entryIndex]._type1._field5 = 0; int v1, v2; - driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, v0, 0x7F); + driver->playSound(trackData, 14, -1, vtStruct->_entries[entryIndex]._voiceNum, v0, 0x7F); driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, voiceType, 0, &v1, &v2); } break; @@ -2295,24 +2320,26 @@ void Sound::_soServiceTrackType1(int trackIndex, const byte *channelData) { vtStruct->_entries[entryIndex]._type1._field5 = 0; int v1, v2; - driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, *(channelData + 1), 0x7f); + driver->playSound(channelData, 14, -1, vtStruct->_entries[entryIndex]._voiceNum, *(channelData + 1), 0x7f); driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, *(channelData + 1), _loop ? 1 : 0, &v1, &v2); + _trkState[trackIndex] = 2; } } else { for (uint entryIndex = 0; entryIndex < vtStruct->_entries.size(); ++entryIndex) { VoiceStructEntry &vte = vtStruct->_entries[entryIndex]; VoiceStructEntryType1 &vse = vte._type1; - if ((vse._sound == this) && (vse._channelNum == channel) && (vse._field4 == vtStruct->_total)) { + if ((vse._sound == this) && (vse._channelNum == channel) && (vse._field4 == *(channelData + 1))) { SoundDriver *driver = vte._driver; - int v1, v2; - driver->proc42(vte._voiceNum, vtStruct->_total, _loop ? 1 : 0, &v1, &v2); - if (v2) { + int isEnded, resetTimer; + driver->proc42(vte._voiceNum, vtStruct->_total, _loop ? 1 : 0, &isEnded, &resetTimer); + if (isEnded) { _trkState[trackIndex] = 0; - } else if (vtStruct->_total) { + } else if (resetTimer) { _timer = 0; } + return; } } @@ -2436,6 +2463,31 @@ void ASound::fade(int fadeDest, int fadeSteps, int fadeTicks, bool stopAfterFade _sound.fade(fadeDest, fadeSteps, fadeTicks, stopAfterFadeFlag); } +void ASound::fadeSound(int soundNum) { + play(soundNum, NULL, 0); + fade(127, 5, 1, false, NULL); +} + +/*--------------------------------------------------------------------------*/ + +ASoundExt::ASoundExt(): ASound() { + _soundNum = 0; +} + +void ASoundExt::synchronize(Serializer &s) { + ASound::synchronize(s); + s.syncAsSint16LE(_soundNum); +} + +void ASoundExt::signal() { + if (_soundNum != 0) { + fadeSound(_soundNum); + } +} + +void ASoundExt::fadeOut2(Action *action) { + fade(0, 10, 10, true, action); +} /*--------------------------------------------------------------------------*/ @@ -2488,7 +2540,12 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() { _opl = OPL::Config::create(); assert(_opl); _opl->init(_sampleRate); - + + _samplesTillCallback = 0; + _samplesTillCallbackRemainder = 0; + _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND; + _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND; + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); Common::set_to(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false); @@ -2558,7 +2615,7 @@ int AdlibSoundDriver::setMasterVolume(int volume) { return oldVolume; } -void AdlibSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) { +void AdlibSoundDriver::playSound(const byte *channelData, int dataOffset, int program, int channel, int v0, int v1) { if (program == -1) return; @@ -2750,34 +2807,38 @@ void AdlibSoundDriver::setFrequency(int channel) { } int AdlibSoundDriver::readBuffer(int16 *buffer, const int numSamples) { - update(buffer, numSamples); - return numSamples; -} - -void AdlibSoundDriver::update(int16 *buf, int len) { - static int samplesLeft = 0; - while (len != 0) { - int count = samplesLeft; - if (count > len) { - count = len; - } - samplesLeft -= count; - len -= count; - _opl->readBuffer(buf, count); - if (samplesLeft == 0) { + Common::StackLock slock1(SoundManager::sfManager()._serverDisabledMutex); + Common::StackLock slock2(SoundManager::sfManager()._serverSuspendedMutex); + + int32 samplesLeft = numSamples; + memset(buffer, 0, sizeof(int16) * numSamples); + while (samplesLeft) { + if (!_samplesTillCallback) { + SoundManager::_sfUpdateCallback(NULL); flush(); - samplesLeft = _sampleRate / 50; + + _samplesTillCallback = _samplesPerCallback; + _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; + if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) { + _samplesTillCallback++; + _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND; + } } - buf += count; + + int32 render = MIN<int>(samplesLeft, _samplesTillCallback); + samplesLeft -= render; + _samplesTillCallback -= render; + + _opl->readBuffer(buffer, render); + buffer += render; } + return numSamples; } /*--------------------------------------------------------------------------*/ -const byte adlibFx_group_data[] = { 3, 1, 1, 0, 0xff }; - -AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() { +SoundBlasterDriver::SoundBlasterDriver(): SoundDriver() { _minVersion = 0x102; _maxVersion = 0x10A; _masterVolume = 0; @@ -2785,167 +2846,99 @@ AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() { _groupData.groupMask = 1; _groupData.v1 = 0x3E; _groupData.v2 = 0; - _groupData.pData = &adlib_group_data[0]; + static byte const group_data[] = { 3, 1, 1, 0, 0xff }; + _groupData.pData = group_data; _mixer = _vm->_mixer; _sampleRate = _mixer->getOutputRate(); - _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); -/* - Common::set_to(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false); - memset(_channelVolume, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v4405E, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v44067, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v44070, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v44079, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - memset(_v44082, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - _v44082[ADLIB_CHANNEL_COUNT] = 0x90; - Common::set_to(_pitchBlend, _pitchBlend + ADLIB_CHANNEL_COUNT, 0x2000); - memset(_v4409E, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); - _patchData = NULL; -*/ + _audioStream = NULL; + _channelData = NULL; } -AdlibFxSoundDriver::~AdlibFxSoundDriver() { +SoundBlasterDriver::~SoundBlasterDriver() { _mixer->stopHandle(_soundHandle); } -bool AdlibFxSoundDriver::open() { - write209(); - write(64); - write(165); - - // for (int idx = 0; idx < 5000 * 16; ++idx) al = port[21h] - -// _v45071 = 1; -// _v4506F = 0; - +bool SoundBlasterDriver::open() { return true; } -void AdlibFxSoundDriver::close() { - write(208); - write211(); - +void SoundBlasterDriver::close() { } -bool AdlibFxSoundDriver::reset() { - +bool SoundBlasterDriver::reset() { return true; } -const GroupData *AdlibFxSoundDriver::getGroupData() { +const GroupData *SoundBlasterDriver::getGroupData() { return &_groupData; } -void AdlibFxSoundDriver::poll() { - if (!_masterVolume || !_channelVolume) { - if (_v45046) - write211(); - } else { - if (!_v45046) - write209(); - } -} - -int AdlibFxSoundDriver::setMasterVolume(int volume) { +int SoundBlasterDriver::setMasterVolume(int volume) { int oldVolume = _masterVolume; _masterVolume = volume; return oldVolume; } -void AdlibFxSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) { - if (program == -1) +void SoundBlasterDriver::playSound(const byte *channelData, int dataOffset, int program, int channel, int v0, int v1) { + if (program != -1) return; - if (_sound) + assert(channel == 0); + + // If sound data has been previously set, then release it + if (_channelData) updateVoice(channel); - // TODO: Stuff + // Set the new channel data + _channelData = channelData + dataOffset; + // Make a copy of the buffer + int dataSize = _vm->_memoryManager.getSize(channelData); + byte *soundData = (byte *)malloc(dataSize - dataOffset); + Common::copy(_channelData, _channelData + (dataSize - dataOffset), soundData); + _audioStream = Audio::makeQueuingAudioStream(11025, false); + _audioStream->queueBuffer(soundData, dataSize - dataOffset, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED); + // Start the new sound + if (!_mixer->isSoundHandleActive(_soundHandle)) + _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, _audioStream); } -void AdlibFxSoundDriver::updateVoice(int channel) { - if (_sound) { - write(208); +void SoundBlasterDriver::updateVoice(int channel) { + // Stop the playing voice + if (_mixer->isSoundHandleActive(_soundHandle)) + _mixer->stopHandle(_soundHandle); - _sound = NULL; - _v45062 = 0; - _v45066 = 0; - _v45068 = 0; - } + _audioStream = NULL; + _channelData = NULL; } -void AdlibFxSoundDriver::proc38(int channel, int cmd, int value) { +void SoundBlasterDriver::proc38(int channel, int cmd, int value) { if (cmd == 7) { // Set channel volume _channelVolume = value; + _mixer->setChannelVolume(_soundHandle, (byte)MIN(255, value * 2)); } } -void AdlibFxSoundDriver::proc42(int channel, int cmd, int value, int *v1, int *v2) { - _v4506A = value; - *v1 = _v4506B; +void SoundBlasterDriver::proc42(int channel, int cmd, int value, int *v1, int *v2) { + // TODO: v2 is used for flagging a reset of the timer. I'm not sure if it's needed + *v1 = 0; *v2 = 0; - _v4506B = 0; - - if (!_sound) - *v2 = 1; -} - -void AdlibFxSoundDriver::write(int v) { - /* - port[adlib_port + 12] = v; - for (int i = 0; i < 100; ++i) { - if (!port[adlib_port + 12] & 0x80) - break; - } - */ -} - -void AdlibFxSoundDriver::flush() { - Common::StackLock slock(SoundManager::sfManager()._serverDisabledMutex); - - // No data output yet -} - - -int AdlibFxSoundDriver::readBuffer(int16 *buffer, const int numSamples) { - update(buffer, numSamples); - return numSamples; -} - -void AdlibFxSoundDriver::update(int16 *buf, int len) { -/* - static int samplesLeft = 0; - while (len != 0) { - int count = samplesLeft; - if (count > len) { - count = len; - } - samplesLeft -= count; - len -= count; - YM3812UpdateOne(_opl, buf, count); - if (samplesLeft == 0) { - flush(); - samplesLeft = _sampleRate / 50; - } - buf += count; + // Note: Checking whether a playing Fx sound had finished was originally done in another + // method in the sample playing code. But since we're using the ScummVM audio soundsystem, + // it's easier simply to do the check right here + if (_audioStream && (_audioStream->numQueuedStreams() == 0)) { + updateVoice(channel); } -*/ -} - -void AdlibFxSoundDriver::write209() { - write(209); - _v45046 = true; -} -void AdlibFxSoundDriver::write211() { - write(211); - _v45046 = false; + if (!_channelData) + // Flag that sound isn't playing + *v1 = 1; } -} // End of namespace tSage +} // End of namespace TsAGE |