diff options
author | Paul Gilbert | 2016-08-06 18:54:00 -0400 |
---|---|---|
committer | Paul Gilbert | 2016-08-06 18:54:00 -0400 |
commit | 7b5b06f9d3618df3b3b9b02c8e4e2a9c897b76da (patch) | |
tree | 8016e149313de227ecf12729fdad2b5e206c1d36 /engines/titanic | |
parent | 551048118cca489eab17e71025c29fbd56ff7b82 (diff) | |
download | scummvm-rg350-7b5b06f9d3618df3b3b9b02c8e4e2a9c897b76da.tar.gz scummvm-rg350-7b5b06f9d3618df3b3b9b02c8e4e2a9c897b76da.tar.bz2 scummvm-rg350-7b5b06f9d3618df3b3b9b02c8e4e2a9c897b76da.zip |
TITANIC: Added more sound manager methods, field renames in CProximity
Diffstat (limited to 'engines/titanic')
-rw-r--r-- | engines/titanic/core/game_object.cpp | 6 | ||||
-rw-r--r-- | engines/titanic/core/game_object.h | 2 | ||||
-rw-r--r-- | engines/titanic/sound/proximity.cpp | 12 | ||||
-rw-r--r-- | engines/titanic/sound/proximity.h | 22 | ||||
-rw-r--r-- | engines/titanic/sound/qmixer.cpp | 30 | ||||
-rw-r--r-- | engines/titanic/sound/qmixer.h | 118 | ||||
-rw-r--r-- | engines/titanic/sound/sound_manager.cpp | 94 | ||||
-rw-r--r-- | engines/titanic/sound/sound_manager.h | 36 | ||||
-rw-r--r-- | engines/titanic/sound/wave_file.cpp | 3 | ||||
-rw-r--r-- | engines/titanic/sound/wave_file.h | 5 | ||||
-rw-r--r-- | engines/titanic/true_talk/true_talk_manager.cpp | 16 |
11 files changed, 301 insertions, 43 deletions
diff --git a/engines/titanic/core/game_object.cpp b/engines/titanic/core/game_object.cpp index d7556c76ff..a366f7f336 100644 --- a/engines/titanic/core/game_object.cpp +++ b/engines/titanic/core/game_object.cpp @@ -634,11 +634,11 @@ void CGameObject::loadSound(const CString &name) { } } -int CGameObject::playSound(const CString &name, int val2, int val3, int val4) { +int CGameObject::playSound(const CString &name, uint volume, int val3, bool repeated) { CProximity prox; - prox._field8 = val2; + prox._channelVolume = volume; prox._fieldC = val3; - prox._field20 = val4; + prox._repeated = repeated; return playSound(name, prox); } diff --git a/engines/titanic/core/game_object.h b/engines/titanic/core/game_object.h index ecef68ce70..e5ee22a8d5 100644 --- a/engines/titanic/core/game_object.h +++ b/engines/titanic/core/game_object.h @@ -183,7 +183,7 @@ protected: /** * Plays a sound */ - int playSound(const CString &name, int val2 = 100, int val3 = 0, int val4 = 0); + int playSound(const CString &name, uint volume = 100, int val3 = 0, bool repeated = false); /** * Plays a sound diff --git a/engines/titanic/sound/proximity.cpp b/engines/titanic/sound/proximity.cpp index af23b7bd5f..4352e9fce8 100644 --- a/engines/titanic/sound/proximity.cpp +++ b/engines/titanic/sound/proximity.cpp @@ -25,12 +25,12 @@ namespace Titanic { -CProximity::CProximity() : _field4(0), _field8(100), _fieldC(0), - _speechHandle(-1), _field14(0), _field18(0), _field1C(1.875), - _field20(0), _field24(10), _field28(0), _field2C(0.0), - _field30(0.5), _field34(0), _posX(0.0), _posY(0.0), _posZ(0.0), - _field44(0), _field48(0), _field4C(0), _field50(0), _field54(0), - _field58(0), _field5C(0), _field60(0), _endTalkerFn(nullptr), +CProximity::CProximity() : _field4(0), _channelVolume(100), _fieldC(0), + _speechHandle(-1), _field14(0), _frequencyMultiplier(0.0), _field1C(1.875), + _repeated(false), _field24(10), _field28(0), _azimuth(0.0), + _range(0.5), _elevation(0), _posX(0.0), _posY(0.0), _posZ(0.0), + _hasVelocity(false), _velocityX(0), _velocityY(0), _velocityZ(0), + _field54(0), _field58(0), _field5C(0), _field60(0), _endTalkerFn(nullptr), _talker(nullptr), _field6C(0) { } diff --git a/engines/titanic/sound/proximity.h b/engines/titanic/sound/proximity.h index 4427574f40..71ea1682d0 100644 --- a/engines/titanic/sound/proximity.h +++ b/engines/titanic/sound/proximity.h @@ -34,25 +34,25 @@ typedef void (*CEndTalkerFn)(TTtalker *talker); class CProximity { public: int _field4; - int _field8; + int _channelVolume; int _fieldC; int _speechHandle; int _field14; - int _field18; - int _field1C; - int _field20; + double _frequencyMultiplier; + double _field1C; + bool _repeated; int _field24; int _field28; - double _field2C; - double _field30; - int _field34; + double _azimuth; + double _range; + double _elevation; double _posX; double _posY; double _posZ; - int _field44; - int _field48; - int _field4C; - int _field50; + bool _hasVelocity; + double _velocityX; + double _velocityY; + double _velocityZ; int _field54; int _field58; int _field5C; diff --git a/engines/titanic/sound/qmixer.cpp b/engines/titanic/sound/qmixer.cpp index 78b3755780..5ece37a579 100644 --- a/engines/titanic/sound/qmixer.cpp +++ b/engines/titanic/sound/qmixer.cpp @@ -41,6 +41,11 @@ int QMixer::qsWaveMixOpenChannel(int iChannel, QMixFlag mode) { return 0; } +int QMixer::qsWaveMixEnableChannel(int iChannel, uint flags, bool enabled) { + // Not currently implemented in ScummVM + return 0; +} + void QMixer::qsWaveMixCloseSession() { _mixer->stopAll(); } @@ -69,4 +74,29 @@ void QMixer::qsWaveMixSetPolarPosition(int iChannel, uint flags, const QSPOLAR & // Not currently implemented in ScummVM } +void QMixer::qsWaveMixSetListenerPosition(const QSVECTOR &position, uint flags) { + // Not currently implemented in ScummVM +} + +void QMixer::qsWaveMixSetListenerOrientation(const QSVECTOR &direction, const QSVECTOR &up, uint flags) { + // Not currently implemented in ScummVM +} + +void QMixer::qsWaveMixSetDistanceMapping(int iChannel, uint flags, const QMIX_DISTANCES &distances) { + // Not currently implemented in ScummVM +} + +void QMixer::qsWaveMixSetFrequency(int iChannel, uint flags, uint frequency) { + // Not currently implemented in ScummVM +} + +void QMixer::qsWaveMixSetSourceVelocity(int iChannel, uint flags, const QSVECTOR &velocity) { + // Not currently implemented in ScummVM +} + +int QMixer::qsWaveMixPlayEx(int iChannel, uint flags, CWaveFile *mixWave, int loops, const QMIXPLAYPARAMS ¶ms) { + // Not currently implemented in ScummVM + return 0; +} + } // End of namespace Titanic z diff --git a/engines/titanic/sound/qmixer.h b/engines/titanic/sound/qmixer.h index 872a517cbc..ca5f6f758d 100644 --- a/engines/titanic/sound/qmixer.h +++ b/engines/titanic/sound/qmixer.h @@ -15,7 +15,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software + * aint with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ @@ -24,6 +24,7 @@ #define TITANIC_QMIXER_H #include "audio/mixer.h" +#include "titanic/sound/wave_file.h" namespace Titanic { @@ -33,7 +34,51 @@ enum QMixFlag { QMIX_OPENCOUNT = 2, // Open iChannel Channels (eg. if iChannel = 4 will create channels 0-3) QMIX_OPENAVAILABLE = 3, // Open the first unopened channel, and return channel number - QMIX_USEONCE = 0x10 // settings are temporary + // Channel function flags + QMIX_ALL = 0x01, // apply to all channels + QMIX_NOREMIX = 0x02, // don't remix + QMIX_CONTROL_NOREMIX = 0x04, // don't remix + QMIX_USEONCE = 0x10, // settings are temporary +}; + +// qsWaveMixEnableChannel flags: if mode==0, use conventional, high-performance +// stereo mixer. Non-zero modes imply some form of additional processing. +enum QMixChannelFlag { + QMIX_CHANNEL_STEREO = 0x0000, // Perform stereo mixing + QMIX_CHANNEL_QSOUND = 0x0001, // Perform QSound localization (default) + QMIX_CHANNEL_DOPPLER = 0x0002, // Calculate velocity using position updates + QMIX_CHANNEL_RANGE = 0x0004, // Do range effects + QMIX_CHANNEL_ELEVATION = 0x0008, // Do elevation effects + QMIX_CHANNEL_NODOPPLERPITCH = 0x0010, // Disable Doppler pitch shift for this channel + QMIX_CHANNEL_PITCH_COPY = 0x0000, // Pitch shifting using copying (fastest) + QMIX_CHANNEL_PITCH_LINEAR = 0x0100, // Pitch shifting using linear interpolation (better but slower) + QMIX_CHANNEL_PITCH_SPLINE = 0x0200, // Pitch shifting using spline interpolation (better yet, but much slower) + QMIX_CHANNEL_PITCH_FILTER = 0x0300, // Pitch shifting using FIR filter (best, but slowest) + QMIX_CHANNEL_PITCH_MASK = 0x0700 // Bits reserved for pitch types +}; + +/** + * Options for dwFlags parameter in QSWaveMixPlayEx. + * + * Notes: The QMIX_USELRUCHANNEL flag has two roles. When QMIX_CLEARQUEUE is also set, + * the channel that has been playing the longest (least-recently-used) is cleared and + * the buffer played. When QMIX_QUEUEWAVE is set, the channel that will first finish + * playing will be selected and the buffer queued to play. Of course, if an unused + * channel is found, it will be selected instead. + * If QMIX_WAIT hasn't been specified, then the channel number will be returned + * in the iChannel field. + */ +enum QMixPlayFlag { + QMIX_QUEUEWAVE = 0x0000, // Queue on channel + QMIX_CLEARQUEUE = 0x0001, // Clear queue on channel + QMIX_USELRUCHANNEL = 0x0002, // See notes above + QMIX_HIGHPRIORITY = 0x0004, + QMIX_WAIT = 0x0008, // Queue to be played with other sounds + QMIX_IMMEDIATE = 0x0020, // Apply volume/pan changes without interpolation + + QMIX_PLAY_SETEVENT = 0x0100, // Calls SetEvent in the original library when done + QMIX_PLAY_PULSEEVENT = 0x0200, // Calls PulseEvent in the original library when done + QMIX_PLAY_NOTIFYSTOP = 0x0400 // Do callback even when stopping or flushing sound }; /** @@ -83,6 +128,35 @@ struct QSPOLAR { azimuth(azimuth_), range(range_), elevation(elevation_) {} }; +struct QMIX_DISTANCES { + int cbSize; // Structure size + double minDistance; // sounds are at full volume if closer than this + double maxDistance; // sounds are muted if further away than this + double scale; // relative amount to adjust rolloff by + + QMIX_DISTANCES() : cbSize(16), minDistance(0.0), maxDistance(0.0), scale(0.0) {} + QMIX_DISTANCES(double minDistance_, double maxDistance_, double scale_) : + cbSize(16), minDistance(minDistance_), maxDistance(maxDistance_), scale(scale_) {} +}; + +typedef void (*LPQMIXDONECALLBACK)(int iChannel, CWaveFile *lpWave, void *dwUser); + +struct QMIXPLAYPARAMS { + uint dwSize; // Size of the play structure + void *lpImage; // Additional preprocessed audio for high performance + uint hwndNotify; // if set, WOM_OPEN and WOM_DONE messages sent to that window + LPQMIXDONECALLBACK callback; // Callback function + void *dwUser; // User data accompanying callback + int lStart; + int lStartLoop; + int lEndLoop; + int lEnd; + const void *lpChannelParams; // initialize with these parameters + + QMIXPLAYPARAMS() : dwSize(36), lpImage(nullptr), hwndNotify(0), callback(nullptr), + dwUser(nullptr), lStart(0), lStartLoop(0), lEndLoop(0), lEnd(0), lpChannelParams(nullptr) {} +}; + /** * This class represents an interface to the QMixer library developed by * QSound Labs, Inc. Which itself is apparently based on Microsoft's @@ -117,6 +191,11 @@ public: int qsWaveMixOpenChannel(int iChannel, QMixFlag mode); /** + * Enables a given channel + */ + int qsWaveMixEnableChannel(int iChannel, uint flags, bool enabled); + + /** * Closes down the mixer */ void qsWaveMixCloseSession(); @@ -161,6 +240,41 @@ public: * @param position Polar position for channel */ void qsWaveMixSetPolarPosition(int iChannel, uint flags, const QSPOLAR &position); + + /** + * Sets the listener position + */ + void qsWaveMixSetListenerPosition(const QSVECTOR &position, uint flags = 0); + + /** + * Sets the listener orientation + */ + void qsWaveMixSetListenerOrientation(const QSVECTOR &direction, const QSVECTOR &up, uint flags = 0); + + /** + * Sets the mapping ditance range + */ + void qsWaveMixSetDistanceMapping(int iChannel, uint flags, const QMIX_DISTANCES &distances); + + /** + * + */ + void qsWaveMixSetFrequency(int iChannel, uint flags, uint frequency); + + /** + * Sets the velocity of the source (listener) + */ + void qsWaveMixSetSourceVelocity(int iChannel, uint flags, const QSVECTOR &velocity); + + /** + * Plays sound + * @param iChannel The channel number to be played on + * @param flags Play flags + * @param mixWave Data for the sound to be played + * @param loops Number of loops to play (-1 for forever) + * @param params Playback parameter data + */ + int qsWaveMixPlayEx(int iChannel, uint flags, CWaveFile *waveFile, int loops, const QMIXPLAYPARAMS ¶ms); }; } // End of namespace Titanic diff --git a/engines/titanic/sound/sound_manager.cpp b/engines/titanic/sound/sound_manager.cpp index 17b53c2d92..d06c18aba1 100644 --- a/engines/titanic/sound/sound_manager.cpp +++ b/engines/titanic/sound/sound_manager.cpp @@ -29,7 +29,7 @@ const uint LATENCY = 100; const uint CHANNELS_COUNT = 16; CSoundManager::CSoundManager() : _musicPercent(75.0), _speechPercent(75.0), - _masterPercent(75.0), _parrotPercent(75.0), _field14(1) { + _masterPercent(75.0), _parrotPercent(75.0), _handleCtr(1) { } /*------------------------------------------------------------------------*/ @@ -52,7 +52,7 @@ void QSoundManagerSounds::flushChannel(int iChannel) { } } -void QSoundManagerSounds::flushChannel(int v1, int iChannel) { +void QSoundManagerSounds::flushChannel(CWaveFile *waveFile, int iChannel) { for (iterator i = begin(); i != end(); ++i) { QSoundManagerSound *item = *i; if (item->_waveFile->isLoaded() && item->_iChannel == iChannel) { @@ -223,12 +223,75 @@ void QSoundManager::setParrotPercent(double percent) { _parrotPercent = percent; } -void QSoundManager::proc29() { - warning("TODO"); +void QSoundManager::setListenerPosition(double posX, double posY, double posZ, + double directionX, double directionY, double directionZ, bool stopSounds) { + if (stopSounds) { + // Stop any running sounds + for (uint idx = 0; idx < _slots.size(); ++idx) { + if (_slots[idx]._val3) + stopSound(_slots[idx]._handle); + } + } + + qsWaveMixSetListenerPosition(QSVECTOR(posX, posY, posZ)); + qsWaveMixSetListenerOrientation(QSVECTOR(directionX, directionY, directionZ), + QSVECTOR(0.0, 0.0, -1.0)); } -void QSoundManager::proc30() { - warning("TODO"); +int QSoundManager::playWave(CWaveFile *waveFile, int iChannel, uint flags, CProximity &prox) { + if (!waveFile || !waveFile->isLoaded()) + return 0; + + prox._channelVolume = CLIP(prox._channelVolume, 0, 100); + prox._fieldC = CLIP(prox._fieldC, -100, 100); + + int slotIndex = findFreeSlot(); + if (slotIndex == -1) + return -1; + + switch (prox._field28) { + case 1: + qsWaveMixSetPolarPosition(iChannel, 8, QSPOLAR(prox._azimuth, prox._range, prox._elevation)); + qsWaveMixEnableChannel(iChannel, QMIX_CHANNEL_ELEVATION, true); + qsWaveMixSetDistanceMapping(iChannel, 8, QMIX_DISTANCES(5.0, 3.0, 1.0)); + break; + + case 2: + qsWaveMixSetSourcePosition(iChannel, 8, QSVECTOR(prox._posX, prox._posY, prox._posZ)); + qsWaveMixEnableChannel(iChannel, QMIX_CHANNEL_ELEVATION, true); + qsWaveMixSetDistanceMapping(iChannel, 8, QMIX_DISTANCES(5.0, 3.0, 1.0)); + break; + + default: + qsWaveMixEnableChannel(iChannel, QMIX_CHANNEL_ELEVATION, true); + qsWaveMixSetPolarPosition(iChannel, 8, QSPOLAR(0.0, 1.0, 0.0)); + break; + } + + if (prox._frequencyMultiplier || prox._field1C != 1.875) { + uint freq = (uint)(waveFile->getFrequency() * prox._frequencyMultiplier); + qsWaveMixSetFrequency(iChannel, 8, freq); + } + + _sounds.add(waveFile, iChannel, prox._endTalkerFn, prox._talker); + + QMIXPLAYPARAMS playParams; + playParams.callback = soundFinished; + playParams.dwUser = this; + if (!qsWaveMixPlayEx(iChannel, flags, waveFile, prox._repeated ? -1 : 0, playParams)) { + Slot &slot = _slots[slotIndex]; + slot._handle = _handleCtr++; + slot._channel = iChannel; + slot._waveFile = waveFile; + slot._val3 = prox._field28; + + return slot._handle; + } else { + _sounds.flushChannel(waveFile, iChannel); + if (prox._field60) + delete waveFile; + return 0; + } } void QSoundManager::soundFreed(Audio::SoundHandle &handle) { @@ -292,4 +355,23 @@ void QSoundManager::updateVolumes() { updateVolume(idx, 250); } +void QSoundManager::soundFinished(int iChannel, CWaveFile *waveFile, void *soundManager) { + static_cast<QSoundManager *>(soundManager)->_sounds.flushChannel(waveFile, iChannel); +} + +int QSoundManager::findFreeSlot() { + for (uint idx = 0; idx < _slots.size(); ++idx) { + if (!_slots[idx]._waveFile) + return idx; + } + + return -1; +} + +void QSoundManager::setChannelVolume(int iChannel, uint volume, uint mode) { + _channelsVolume[iChannel] = volume; + _channelsMode[iChannel] = mode; + updateVolume(iChannel, 250); +} + } // End of namespace Titanic z diff --git a/engines/titanic/sound/sound_manager.h b/engines/titanic/sound/sound_manager.h index b0591ce277..ce9ef7f2d3 100644 --- a/engines/titanic/sound/sound_manager.h +++ b/engines/titanic/sound/sound_manager.h @@ -41,7 +41,7 @@ protected: double _speechPercent; double _masterPercent; double _parrotPercent; - int _field14; + uint _handleCtr; public: CSoundManager(); virtual ~CSoundManager() {} @@ -211,7 +211,7 @@ public: /** * Flushes a wave file attached to the specified channel */ - void flushChannel(int v1, int iChannel); + void flushChannel(CWaveFile *waveFile, int iChannel); /** * Returns true if the list contains the specified wave file @@ -225,12 +225,13 @@ public: */ class QSoundManager : public CSoundManager, public QMixer { struct Slot { - uint _val1; + CWaveFile *_waveFile; uint _val2; uint _ticks; int _channel; uint _handle; - Slot() : _val1(0), _val2(0), _ticks(0), _channel(0), _handle(0) {} + uint _val3; + Slot() : _waveFile(0), _val2(0), _ticks(0), _channel(0), _handle(0), _val3(0) {} }; private: QSoundManagerSounds _sounds; @@ -254,6 +255,21 @@ private: * Updates all the volumes */ void updateVolumes(); + + /** + * Called by the QMixer when a sound finishes playing + */ + static void soundFinished(int iChannel, CWaveFile *waveFile, void *soundManager); + + /** + * Finds the first free slot + */ + int findFreeSlot(); + + /** + * Sets a channel volume + */ + void setChannelVolume(int iChannel, uint volume, uint mode); public: int _field18; int _field1C; @@ -361,8 +377,16 @@ public: */ virtual void setParrotPercent(double percent); - virtual void proc29(); - virtual void proc30(); + /** + * Sets the position and orientation for the listener (player) + */ + virtual void setListenerPosition(double posX, double posY, double posZ, + double directionX, double directionY, double directionZ, bool stopSounds); + + /** + * Starts a wave file playing + */ + virtual int playWave(CWaveFile *waveFile, int iChannel, uint flags, CProximity &prox); /** * Called when a wave file is freed diff --git a/engines/titanic/sound/wave_file.cpp b/engines/titanic/sound/wave_file.cpp index 6f0007f511..adbc41455d 100644 --- a/engines/titanic/sound/wave_file.cpp +++ b/engines/titanic/sound/wave_file.cpp @@ -51,5 +51,8 @@ bool CWaveFile::loadSound(const CString &name) { return true; } +uint CWaveFile::getFrequency() const { + return _stream->getRate(); +} } // End of namespace Titanic z diff --git a/engines/titanic/sound/wave_file.h b/engines/titanic/sound/wave_file.h index ff85df5bd0..7818c1386d 100644 --- a/engines/titanic/sound/wave_file.h +++ b/engines/titanic/sound/wave_file.h @@ -52,6 +52,11 @@ public: * Returns true if the wave file has data loaded */ bool isLoaded() const { return _stream != nullptr; } + + /** + * Return the frequency of the loaded wave file + */ + uint getFrequency() const; }; } // End of namespace Titanic diff --git a/engines/titanic/true_talk/true_talk_manager.cpp b/engines/titanic/true_talk/true_talk_manager.cpp index da3336f432..2de40eef15 100644 --- a/engines/titanic/true_talk/true_talk_manager.cpp +++ b/engines/titanic/true_talk/true_talk_manager.cpp @@ -504,17 +504,17 @@ void CTrueTalkManager::playSpeech(TTtalker *talker, TTroomScript *roomScript, CV } if (milli > 0) { - p3._field8 = (index * 3) / 2; + p3._channelVolume = (index * 3) / 2; p3._field28 = 1; - p3._field2C = -135.0; - p3._field30 = 1.0; - p3._field34 = 0; + p3._azimuth = -135.0; + p3._range = 1.0; + p3._elevation = 0; - p2._field8 = (index * 3) / 4; + p2._channelVolume = (index * 3) / 4; p2._field28 = 0; - p2._field2C = 135.0; - p2._field30 = 1.0; - p2._field34 = 0; + p2._azimuth = 135.0; + p2._range = 1.0; + p2._elevation = 0; } _gameManager->_sound.managerProc8(p1._field24); |