diff options
author | Paul Gilbert | 2011-06-27 22:54:28 +1000 |
---|---|---|
committer | Paul Gilbert | 2011-06-27 22:56:14 +1000 |
commit | 6cea946f16cee1529863b0d5ca77cfbf4bfb01b1 (patch) | |
tree | e37a123e260ca49a91ae20289e1b041eae57f29c /engines | |
parent | 0a9b9fe08f3b5fa8f9a505887fccd88b42f7f1b9 (diff) | |
download | scummvm-rg350-6cea946f16cee1529863b0d5ca77cfbf4bfb01b1.tar.gz scummvm-rg350-6cea946f16cee1529863b0d5ca77cfbf4bfb01b1.tar.bz2 scummvm-rg350-6cea946f16cee1529863b0d5ca77cfbf4bfb01b1.zip |
TSAGE: Separated the sound manager processing into it's own thread
This will be necessary with the introduction of the Sound FX driver, since the sound manager will do the processing for both drivers, but each will need to do their own output in their AudioStream thread
Diffstat (limited to 'engines')
-rw-r--r-- | engines/tsage/events.h | 1 | ||||
-rw-r--r-- | engines/tsage/sound.cpp | 344 | ||||
-rw-r--r-- | engines/tsage/sound.h | 73 |
3 files changed, 382 insertions, 36 deletions
diff --git a/engines/tsage/events.h b/engines/tsage/events.h index a13455d378..e0fbd88745 100644 --- a/engines/tsage/events.h +++ b/engines/tsage/events.h @@ -37,6 +37,7 @@ enum EventType {EVENT_NONE = 0, EVENT_BUTTON_DOWN = 1, EVENT_BUTTON_UP = 2, EVEN enum ButtonShiftFlags {BTNSHIFT_LEFT = 0, BTNSHIFT_RIGHT = 3, BTNSHIFT_MIDDLE = 4}; // Intrinisc game delay between execution frames. This runs at 60Hz +#define GAME_FRAME_RATE 60 #define GAME_FRAME_TIME (1000 / 60) class GfxManager; diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp index 2c00e6ec47..01e770a77a 100644 --- a/engines/tsage/sound.cpp +++ b/engines/tsage/sound.cpp @@ -31,25 +31,6 @@ namespace tSage { static SoundManager *_soundManager = NULL; -#if 0 -static void dumpVoiceStruct() { - VoiceTypeStruct *vt = _soundManager->_voiceTypeStructPtrs[1]; - if (!vt) { - debug("Not setup"); - return; - } - - assert(vt->_voiceType == VOICETYPE_1); - for (uint idx = 0; idx < vt->_entries.size(); ++idx) { - VoiceStructEntryType1 &vte = vt->_entries[idx]._type1; - debug("#%d - s=%p, ch=%x, pr=%x | s2=%p, ch2=%x, pr2=%x | s3=%p, ch3=%x, pr3=%x", - idx, (void *)vte._sound, vte._channelNum, vte._priority, - (void *)vte._sound2, vte._channelNum2, vte._priority2, - (void *)vte._sound3, vte._channelNum3, vte._priority3); - } -} -#endif - /*--------------------------------------------------------------------------*/ SoundManager::SoundManager() { @@ -84,6 +65,8 @@ SoundManager::~SoundManager() { delete driver; } _sfTerminate(); + + g_system->getTimerManager()->removeTimerProc(_sfUpdateCallback); } _soundManager = NULL; @@ -94,6 +77,10 @@ void SoundManager::postInit() { _saver->addSaveNotifier(&SoundManager::saveNotifier); _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); + __sndmgrReady = true; } } @@ -1330,7 +1317,6 @@ bool SoundManager::_sfInstallDriver(SoundDriver *driver) { if (!driver->open()) return false; - driver->setUpdateCallback(_sfUpdateCallback, (void *)&sfManager()); sfManager()._installedDrivers.push_back(driver); driver->_groupOffset = driver->getGroupData(); driver->_groupMask = READ_LE_UINT32(driver->_groupOffset); @@ -2444,8 +2430,6 @@ const int v440D4[48] = { }; AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() { - _upCb = NULL; - _upRef = NULL; _minVersion = 0x102; _maxVersion = 0x10A; _masterVolume = 0; @@ -2586,7 +2570,16 @@ void AdlibSoundDriver::setPitch(int channel, int pitchBlend) { void AdlibSoundDriver::write(byte reg, byte value) { _portContents[reg] = value; - OPLWriteReg(_opl, reg, value); + _queue.push(RegisterValue(reg, value)); +} + +void AdlibSoundDriver::flush() { + Common::StackLock slock(SoundManager::sfManager()._serverDisabledMutex); + + while (!_queue.empty()) { + RegisterValue v = _queue.pop(); + OPLWriteReg(_opl, v._regNum, v._value); + } } void AdlibSoundDriver::updateChannelVolume(int channelNum) { @@ -2725,18 +2718,311 @@ void AdlibSoundDriver::update(int16 *buf, int len) { len -= count; YM3812UpdateOne(_opl, buf, count); if (samplesLeft == 0) { - if (_upCb) { - (*_upCb)(_upRef); - } + flush(); samplesLeft = _sampleRate / 50; } buf += count; } } -void AdlibSoundDriver::setUpdateCallback(UpdateCallback upCb, void *ref) { - _upCb = upCb; - _upRef = ref; +/*--------------------------------------------------------------------------*/ + +const byte adlibFx_group_data[] = { 3, 1, 1, 0, 0xff }; + + +AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() { + _minVersion = 0x102; + _maxVersion = 0x10A; + _masterVolume = 0; + + _groupData.groupMask = 9; + _groupData.v1 = 0x3E; + _groupData.v2 = 0; + _groupData.pData = &adlib_group_data[0]; + + _mixer = _vm->_mixer; + _sampleRate = _mixer->getOutputRate(); + _opl = makeAdLibOPL(_sampleRate); + _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; +*/ +} + +AdlibFxSoundDriver::~AdlibFxSoundDriver() { + _mixer->stopHandle(_soundHandle); + OPLDestroy(_opl); +} + +bool AdlibFxSoundDriver::open() { + + + write(1, 0x20); + if (!reset()) + return false; + + write(8, 0); + for (int idx = 0x20; idx < 0xF6; ++idx) + write(idx, 0); + + write(0xBD, 0); + return true; +} + +void AdlibFxSoundDriver::close() { + for (int idx = 0xB0; idx < 0xB8; ++idx) + write(idx, _portContents[idx] & 0xDF); + for (int idx = 0x40; idx < 0x55; ++idx) + write(idx, 0x3F); + reset(); +} + +bool AdlibFxSoundDriver::reset() { + write(1, 0x20); + write(1, 0x20); + + return true; +} + +const GroupData *AdlibFxSoundDriver::getGroupData() { + return &_groupData; +} + +int AdlibFxSoundDriver::setMasterVolume(int volume) { + int oldVolume = _masterVolume; + _masterVolume = volume; + + for (int channelNum = 0; channelNum < ADLIB_CHANNEL_COUNT; ++channelNum) + updateChannelVolume(channelNum); + + return oldVolume; +} + +void AdlibFxSoundDriver::proc32(int channel, int program, int v0, int v1) { + if (program == -1) + return; +/* + int offset = READ_LE_UINT16(_patchData + program * 2); + if (offset) { + const byte *dataP = _patchData + offset; + int id; + + for (offset = 2, id = 0; id != READ_LE_UINT16(dataP); offset += 30, ++id) { + if ((dataP[offset] <= v0) && (dataP[offset + 1] >= v0)) { + if (dataP[offset + 2] != 0xff) + v0 = dataP[offset + 2]; + + _v4409E[channel] = dataP + offset - _patchData; + + // Set sustain/release + int portNum = v440C2[v440B0[channel]] + 0x80; + write(portNum, (_portContents[portNum] & 0xF0) | 0xF); + + portNum = v440C2[v440B9[channel]] + 0x80; + write(portNum, (_portContents[portNum] & 0xF0) | 0xF); + + if (_channelVoiced[channel]) + clearVoice(channel); + + _v44067[channel] = v0; + _v4405E[channel] = v1; + + updateChannel(channel); + setFrequency(channel); + updateChannelVolume(channel); + setVoice(channel); + break; + } + } + } + */ +} + +void AdlibFxSoundDriver::updateVoice(int channel) { + if (_channelVoiced[channel]) + clearVoice(channel); +} + +void AdlibFxSoundDriver::proc38(int channel, int cmd, int value) { + if (cmd == 7) { + // Set channel volume + _channelVolume[channel] = value; + updateChannelVolume(channel); + } +} + +void AdlibFxSoundDriver::setPitch(int channel, int pitchBlend) { + _pitchBlend[channel] = pitchBlend; + setFrequency(channel); +} + +void AdlibFxSoundDriver::write(byte reg, byte value) { + _portContents[reg] = value; + _queue.push(RegisterValue(reg, value)); +} + +void AdlibFxSoundDriver::flush() { + Common::StackLock slock(SoundManager::sfManager()._serverDisabledMutex); + + while (!_queue.empty()) { + RegisterValue v = _queue.pop(); + OPLWriteReg(_opl, v._regNum, v._value); + } +} + +void AdlibFxSoundDriver::updateChannelVolume(int channelNum) { + int volume = (_masterVolume * _channelVolume[channelNum] / 127 * _v4405E[channelNum] / 127) / 2; + int level2 = 63 - v44134[volume * _v44079[channelNum] / 63]; + int level1 = !_v44082[channelNum] ? 63 - _v44070[channelNum] : + 63 - v44134[volume * _v44070[channelNum] / 63]; + + int portNum = v440C2[v440B0[channelNum]] + 0x40; + write(portNum, (_portContents[portNum] & 0x80) | level1); + + portNum = v440C2[v440B9[channelNum]] + 0x40; + write(portNum, (_portContents[portNum] & 0x80) | level2); +} + +void AdlibFxSoundDriver::setVoice(int channel) { + int portNum = 0xB0 + channel; + write(portNum, _portContents[portNum] | 0x20); + _channelVoiced[channel] = true; +} + +void AdlibFxSoundDriver::clearVoice(int channel) { + write(0xB0 + channel, _portContents[0xB0 + channel] & ~0x20); + _channelVoiced[channel] = false; +} + +void AdlibFxSoundDriver::updateChannel(int channel) { +/* + const byte *dataP = _patchData + _v4409E[channel]; + int portOffset = v440C2[v440B0[channel]]; + + int portNum = portOffset + 0x20; + int portValue = 0; + if (*(dataP + 4)) + portValue |= 0x80; + if (*(dataP + 5)) + portValue |= 0x40; + if (*(dataP + 8)) + portValue |= 0x20; + if (*(dataP + 6)) + portValue |= 0x10; + portValue |= *(dataP + 7); + write(portNum, portValue); + + portValue = (_portContents[0x40 + portOffset] & 0x3F) | (*(dataP + 9) << 6); + write(0x40 + portOffset, portValue); + + _v44070[channel] = 63 - *(dataP + 10); + write(0x60 + portOffset, *(dataP + 12) | (*(dataP + 11) << 4)); + write(0x80 + portOffset, *(dataP + 14) | (*(dataP + 13) << 4)); + write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 15)); + + portOffset = v440C2[v440B9[channel]]; + portNum = portOffset + 0x20; + portValue = 0; + if (*(dataP + 17)) + portValue |= 0x80; + if (*(dataP + 18)) + portValue |= 0x40; + if (*(dataP + 21)) + portValue |= 0x20; + if (*(dataP + 19)) + portValue |= 0x10; + portValue |= *(dataP + 20); + write(portNum, portValue); + + write(0x40 + portOffset, (_portContents[0x40 + portOffset] & 0x3f) | (*(dataP + 22) << 6)); + _v44079[channel] = 0x3F - *(dataP + 23); + write(0x60 + portOffset, *(dataP + 25) | (*(dataP + 24) << 4)); + write(0x80 + portOffset, *(dataP + 27) | (*(dataP + 26) << 4)); + write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 28)); + + write(0xC0 + channel, (_portContents[0xC0 + channel] & 0xF0) + | (*(dataP + 16) << 1) | *(dataP + 3)); + + _v44082[channel] = *(dataP + 3); + */ +} + +void AdlibFxSoundDriver::setFrequency(int channel) { + int offset, ch; + + int v = _pitchBlend[channel]; + if (v == 0x2000) { + offset = 0; + ch = _v44067[channel]; + } else if (v > 0x2000) { + ch = _v44067[channel]; + v -= 0x2000; + if (v == 0x1fff) + v = 0x2000; + + offset = (v / 170) & 3; + ch += (v / 170) >> 2; + + if (ch >= 128) + ch = 127; + } else { + ch = _v44067[channel]; + int tempVal = (0x2000 - v) / 170; + int tempVal2 = 4 - (tempVal & 3); + + if (tempVal2 == 4) + offset = 0; + else { + offset = tempVal2; + --ch; + } + + ch -= tempVal >> 2; + if (ch < 0) + ch = 0; + } + + int var2 = ch / 12; + if (var2) + --var2; + + int dataWord = v440D4[((ch % 12) << 2) + offset]; + write(0xA0 + channel, dataWord & 0xff); + write(0xB0 + channel, (_portContents[0xB0 + channel] & 0xE0) | + ((dataWord >> 8) & 3) | (var2 << 2)); +} + +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; + } } } // End of namespace tSage diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h index 4647e3c564..27f30b9b08 100644 --- a/engines/tsage/sound.h +++ b/engines/tsage/sound.h @@ -25,6 +25,7 @@ #include "common/scummsys.h" #include "common/mutex.h" +#include "common/queue.h" #include "audio/audiostream.h" #include "audio/fmopl.h" #include "audio/mixer.h" @@ -65,6 +66,15 @@ struct GroupData { const byte *pData; }; +struct RegisterValue { + uint8 _regNum; + uint8 _value; + + RegisterValue(int regNum, int value) { + _regNum = regNum; _value = value; + } +}; + class SoundDriver { public: Common::String _shortDescription, _longDescription; @@ -73,10 +83,6 @@ public: uint32 _groupMask; const GroupData *_groupOffset; int _driverResID; - - typedef void (*UpdateCallback)(void *); - UpdateCallback _upCb; - void *_upRef; public: SoundDriver(); virtual ~SoundDriver() {}; @@ -106,8 +112,6 @@ public: virtual void proc38(int channel, int cmd, int value) {} // Method #19 virtual void setPitch(int channel, int pitchBlend) {} // Method #20 virtual void proc42(int channel, int v0, int v1) {} // Method #21 - - virtual void setUpdateCallback(UpdateCallback upCb, void *ref) {} }; struct VoiceStructEntryType0 { @@ -405,6 +409,7 @@ private: byte _portContents[256]; const byte *_patchData; int _masterVolume; + Common::Queue<RegisterValue> _queue; bool _channelVoiced[ADLIB_CHANNEL_COUNT]; int _channelVolume[ADLIB_CHANNEL_COUNT]; @@ -418,6 +423,7 @@ private: void write(byte reg, byte value); + void flush(); void updateChannelVolume(int channel); void setVoice(int channel); void clearVoice(int channel); @@ -437,7 +443,6 @@ public: virtual void updateVoice(int channel); virtual void proc38(int channel, int cmd, int value); virtual void setPitch(int channel, int pitchBlend); - virtual void setUpdateCallback(UpdateCallback upCb, void *ref); // AudioStream interface virtual int readBuffer(int16 *buffer, const int numSamples); @@ -448,6 +453,60 @@ public: void update(int16 *buf, int len); }; +class AdlibFxSoundDriver: public SoundDriver, Audio::AudioStream { +private: + GroupData _groupData; + Audio::Mixer *_mixer; + FM_OPL *_opl; + Audio::SoundHandle _soundHandle; + int _sampleRate; + byte _portContents[256]; + int _masterVolume; + Common::Queue<RegisterValue> _queue; + + bool _channelVoiced[ADLIB_CHANNEL_COUNT]; + int _channelVolume[ADLIB_CHANNEL_COUNT]; + int _v4405E[ADLIB_CHANNEL_COUNT]; + int _v44067[ADLIB_CHANNEL_COUNT]; + int _v44070[ADLIB_CHANNEL_COUNT]; + int _v44079[ADLIB_CHANNEL_COUNT]; + int _v44082[ADLIB_CHANNEL_COUNT + 1]; + int _pitchBlend[ADLIB_CHANNEL_COUNT]; + int _v4409E[ADLIB_CHANNEL_COUNT]; + + + void write(byte reg, byte value); + void flush(); + void updateChannelVolume(int channel); + void setVoice(int channel); + void clearVoice(int channel); + void updateChannel(int channel); + void setFrequency(int channel); +public: + AdlibFxSoundDriver(); + virtual ~AdlibFxSoundDriver(); + + virtual bool open(); + virtual void close(); + virtual bool reset(); + virtual const GroupData *getGroupData(); + virtual void installPatch(const byte *data, int size) {} + virtual int setMasterVolume(int volume); + virtual void proc32(int channel, int program, int v0, int v1); + virtual void updateVoice(int channel); + virtual void proc38(int channel, int cmd, int value); + virtual void setPitch(int channel, int pitchBlend); + + // AudioStream interface + virtual int readBuffer(int16 *buffer, const int numSamples); + virtual bool isStereo() const { return false; } + virtual bool endOfData() const { return false; } + virtual int getRate() const { return _sampleRate; } + + void update(int16 *buf, int len); +}; + + } // End of namespace tSage #endif |