aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sword2/driver/d_sound.cpp1336
-rw-r--r--sword2/driver/d_sound.h124
-rw-r--r--sword2/driver/driver96.h20
-rw-r--r--sword2/sound.cpp7
4 files changed, 731 insertions, 756 deletions
diff --git a/sword2/driver/d_sound.cpp b/sword2/driver/d_sound.cpp
index 563433eac4..0310978eed 100644
--- a/sword2/driver/d_sound.cpp
+++ b/sword2/driver/d_sound.cpp
@@ -39,9 +39,6 @@
namespace Sword2 {
-// Fade-out takes half a second. This may need some tuning.
-#define FADE_SAMPLES 11025
-
static File fpMus;
// Decompression macros
@@ -49,12 +46,142 @@ static File fpMus;
#define GetCompressedSign(n) (((n) >> 3) & 1)
#define GetCompressedAmplitude(n) ((n) & 7)
-static int32 musicVolTable[17] = {
+static void premix_proc(void *param, int16 *data, uint len) {
+ ((Sound *) param)->fxServer(data, len);
+}
+
+Sound::Sound(Sword2Engine *vm) {
+ _vm = vm;
+ _mutex = _vm->_system->create_mutex();
+
+ memset(_fx, 0, sizeof(_fx));
+
+ _soundOn = true;
+
+ _speechStatus = false;
+ _speechPaused = false;
+ _speechMuted = false;
+ _speechVol = 14;
+
+ _fxPaused = false;
+ _fxMuted = false;
+ _fxVol = 14;
+
+ _musicVol = 16;
+ _musicMuted = false;
+
+ _converter = makeRateConverter(_music[0].getRate(), _vm->_mixer->getOutputRate(), _music[0].isStereo(), false);
+
+ _vm->_mixer->setupPremix(premix_proc, this);
+}
+
+Sound::~Sound() {
+ _vm->_mixer->setupPremix(0, 0);
+ if (_mutex)
+ _vm->_system->delete_mutex(_mutex);
+}
+
+void Sound::fxServer(int16 *data, uint len) {
+ Common::StackLock lock(_mutex);
+
+ if (!_soundOn)
+ return;
+
+ updateCompSampleStreaming(data, len);
+
+ if (!_music[0]._streaming && !_music[1]._streaming && fpMus.isOpen())
+ fpMus.close();
+}
+
+/**
+ * This function creates the pan table.
+ */
+
+// FIXME: Could we use the FLAG_REVERSE_STEREO mixer flag instead?
+
+void Sound::buildPanTable(bool reverse) {
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ _panTable[i] = -127 + i * 8;
+ _panTable[i + 17] = (i + 1) * 8 - 1;
+ }
+
+ _panTable[16] = 0;
+
+ if (reverse) {
+ for (i = 0; i < 33; i++)
+ _panTable[i] = -_panTable[i];
+ }
+}
+
+// ----------------------------------------------------------------------------
+// MUSIC
+// ----------------------------------------------------------------------------
+
+// All music is encoded at 22050 Hz so this means fading takes 3 seconds.
+#define FADE_SAMPLES 66150
+
+int32 Sound::_musicVolTable[17] = {
0, 15, 31, 47, 63, 79, 95, 111, 127,
143, 159, 175, 191, 207, 223, 239, 255
};
-int16 MusicHandle::read() {
+void MusicHandle::fadeDown(void) {
+ if (_fading < 0)
+ _fading = -_fading;
+ else if (_fading == 0)
+ _fading = FADE_SAMPLES;
+}
+
+void MusicHandle::fadeUp(void) {
+ if (_fading > 0)
+ _fading = -_fading;
+ else if (_fading == 0)
+ _fading = -FADE_SAMPLES;
+}
+
+int32 MusicHandle::play(const char *filename, uint32 musicId, bool looping) {
+ // The assumption here is that we are never playing music from two
+ // different files at the same time.
+
+ if (!fpMus.isOpen())
+ fpMus.open(filename);
+
+ if (!fpMus.isOpen())
+ return RDERR_INVALIDFILENAME;
+
+ fpMus.seek((musicId + 1) * 8, SEEK_SET);
+ _fileStart = fpMus.readUint32LE();
+
+ uint32 len = fpMus.readUint32LE();
+
+ if (!_fileStart || !len)
+ return RDERR_INVALIDID;
+
+ _fileEnd = _fileStart + len;
+ _filePos = _fileStart;
+ _streaming = true;
+ _firstTime = true;
+ _looping = looping;
+ fadeUp();
+ return RD_OK;
+}
+
+void MusicHandle::stop(void) {
+ _streaming = false;
+ _looping = false;
+ _fading = 0;
+}
+
+int MusicHandle::readBuffer(int16 *buffer, const int numSamples) {
+ int samples;
+ for (samples = 0; samples < numSamples && !endOfData(); samples++)
+ *buffer++ = read();
+ return samples;
+}
+
+int16 MusicHandle::read(void) {
uint8 in;
uint16 delta;
int16 out;
@@ -89,11 +216,9 @@ int16 MusicHandle::read() {
fpMus.seek(_filePos, SEEK_SET);
}
} else {
- // Fade out at the end of the music. Is this really desirable
- // behaviour?
-
- if (_fileEnd - _filePos <= FADE_SAMPLES)
- _fading = _fileEnd - _filePos;
+ // Fade out at the end of the music, unless it already is.
+ if (_fileEnd - _filePos <= FADE_SAMPLES && _fading <= 0)
+ fadeDown();
}
if (_fading > 0) {
@@ -102,87 +227,107 @@ int16 MusicHandle::read() {
_looping = false;
}
out = (out * _fading) / FADE_SAMPLES;
+ } else if (_fading < 0) {
+ _fading++;
+ out = (out * (FADE_SAMPLES + _fading)) / FADE_SAMPLES;
}
return out;
}
-bool MusicHandle::endOfData() const {
+bool MusicHandle::endOfData(void) const {
return (!_streaming || _filePos >= _fileEnd);
}
-static void premix_proc(void *param, int16 *data, uint len) {
- ((Sound *) param)->fxServer(data, len);
+/**
+ * Mutes/Unmutes the music.
+ * @param mute If mute is false, restore the volume to the last set master
+ * level. Otherwise the music is muted (volume 0).
+ */
+
+void Sound::muteMusic(bool mute) {
+ _musicMuted = mute;
}
-Sound::Sound(Sword2Engine *vm) {
- _vm = vm;
- _mutex = _vm->_system->create_mutex();
+/**
+ * @return the music's mute state, true if mute, false if not mute
+ */
- _soundOn = false;
- _speechStatus = false;
- _fxPaused = false;
- _speechPaused = false;
- _speechVol = 14;
- _fxVol = 14;
- _speechMuted = 0;
- _fxMuted = 0;
- _musicVol = 16;
+bool Sound::isMusicMute(void) {
+ return _musicMuted;
+}
- _musicMuted = 0;
+/**
+ * Set the volume of any future as well as playing music.
+ * @param volume volume, from 0 (silent) to 16 (max)
+ */
- memset(_fx, 0, sizeof(_fx));
+void Sound::setMusicVolume(uint8 volume) {
+ if (volume > 16)
+ volume = 16;
- _soundOn = true;
+ _musicVol = volume;
+}
- _converter = makeRateConverter(_music[0].getRate(), _vm->_mixer->getOutputRate(), _music[0].isStereo(), false);
+/**
+ * @return the volume setting for music
+ */
- _vm->_mixer->setupPremix(premix_proc, this);
+uint8 Sound::getMusicVolume(void) {
+ return _musicVol;
}
-Sound::~Sound() {
- _vm->_mixer->setupPremix(0, 0);
- if (_mutex)
- _vm->_system->delete_mutex(_mutex);
-}
+/**
+ * Stops the music dead in its tracks. Any music that is currently being
+ * streamed is paused.
+ */
-// --------------------------------------------------------------------------
-// This function reverse the pan table, thus reversing the stereo.
-// --------------------------------------------------------------------------
+void Sound::pauseMusic(void) {
+ Common::StackLock lock(_mutex);
-// FIXME: We could probably use the FLAG_REVERSE_STEREO mixer flag here.
+ if (_soundOn) {
+ for (int i = 0; i < MAXMUS; i++)
+ _music[i]._paused = true;
+ }
+}
/**
- * This function creates the pan table.
+ * Restarts the music from where it was stopped.
*/
-void Sound::buildPanTable(bool reverse) {
- int i;
+void Sound::unpauseMusic(void) {
+ Common::StackLock lock(_mutex);
- for (i = 0; i < 16; i++) {
- _panTable[i] = -127 + i * 8;
- _panTable[i + 17] = (i + 1) * 8 - 1;
+ if (_soundOn) {
+ for (int i = 0; i < MAXMUS; i++)
+ _music[i]._paused = false;
}
+}
- _panTable[16] = 0;
+/**
+ * Fades out and stops the music.
+ */
- if (reverse) {
- for (i = 0; i < 33; i++)
- _panTable[i] = -_panTable[i];
- }
+void Sound::stopMusic(void) {
+ Common::StackLock lock(_mutex);
+
+ for (int i = 0; i < MAXMUS; i++)
+ _music[i].fadeDown();
}
-// Save/Restore information about current music so that we can restore it
-// after the credits.
+/**
+ * Save/Restore information about current music so that we can restore it
+ * after the credits.
+ */
-void Sound::saveMusicState() {
+void Sound::saveMusicState(void) {
Common::StackLock lock(_mutex);
int saveStream;
- if (_music[0]._streaming && !_music[0]._fading) {
+ if (_music[0]._streaming && _music[0]._fading <= 0) {
saveStream = 0;
- } else if (_music[1]._streaming && !_music[0]._fading) {
+ } else if (_music[1]._streaming && _music[0]._fading <= 0) {
saveStream = 1;
} else {
_music[2]._streaming = false;
@@ -204,7 +349,7 @@ void Sound::saveMusicState() {
savedMusicFilename = NULL;
}
-void Sound::restoreMusicState() {
+void Sound::restoreMusicState(void) {
Common::StackLock lock(_mutex);
int restoreStream;
@@ -215,15 +360,14 @@ void Sound::restoreMusicState() {
// Fade out any music that happens to be playing
for (int i = 0; i < MAXMUS; i++) {
- if (_music[i]._streaming && !_music[i]._fading)
- _music[i]._fading = FADE_SAMPLES;
+ if (_music[i]._streaming)
+ _music[i].fadeDown();
}
- if (!_music[0]._streaming && !_music[0]._fading) {
+ if (!_music[0]._streaming)
restoreStream = 0;
- } else {
+ else
restoreStream = 1;
- }
_music[restoreStream]._streaming = true;
_music[restoreStream]._fading = 0;
@@ -232,6 +376,7 @@ void Sound::restoreMusicState() {
_music[restoreStream]._filePos = _music[2]._filePos;
_music[restoreStream]._fileEnd = _music[2]._fileEnd;
_music[restoreStream]._lastSample = _music[2]._lastSample;
+ _music[restoreStream].fadeUp();
if (savedMusicFilename) {
if (fpMus.isOpen())
@@ -264,41 +409,274 @@ void Sound::playLeadOut(uint8 *leadOut) {
}
}
-// --------------------------------------------------------------------------
-// This function returns the index of the sound effect with the ID passed in.
-// --------------------------------------------------------------------------
+/**
+ * Streams music from a cluster file.
+ * @param filename the file name of the music cluster file
+ * @param musicId the id of the music to stream
+ * @param looping true if the music is to loop back to the start
+ * @return RD_OK or an error code
+ */
-int32 Sound::getFxIndex(int32 id) {
- for (int i = 0; i < MAXFX; i++) {
- if (_fx[i]._id == id)
- return i;
+int32 Sound::streamCompMusic(const char *filename, uint32 musicId, bool looping) {
+ Common::StackLock lock(_mutex);
+
+ int32 primaryStream = -1;
+ int32 secondaryStream = -1;
+
+ // If both music streams are playing, that should mean one of them is
+ // fading out. Pick that one, and stop it completely.
+
+ if (_music[0]._streaming && _music[1]._streaming) {
+ if (_music[0]._fading > 0)
+ primaryStream = 0;
+ else
+ primaryStream = 1;
+
+ _music[primaryStream].stop();
}
- return MAXFX;
+ // Pick the available music stream. If no music is playing it doesn't
+ // matter which we use, so pick the first one.
+
+ if (_music[0]._streaming || _music[1]._streaming) {
+ if (_music[0]._streaming) {
+ primaryStream = 1;
+ secondaryStream = 0;
+ } else {
+ primaryStream = 0;
+ secondaryStream = 1;
+ }
+ } else
+ primaryStream = 0;
+
+ // Don't start streaming if the volume is off.
+ if (isMusicMute())
+ return RD_OK;
+
+ // Start other music stream fading out
+ if (secondaryStream != -1)
+ _music[secondaryStream].fadeDown();
+
+ return _music[primaryStream].play(filename, musicId, looping);
}
-int32 Sound::isFxOpen(int32 id) {
- // FIXME: This seems backwards to me, but changing it breaks sound.
- return getFxIndex(id) == MAXFX;
+void Sound::updateCompSampleStreaming(int16 *data, uint len) {
+ for (int i = 0; i < MAXMUS; i++) {
+ if (!_music[i]._streaming || _music[i]._paused)
+ continue;
+
+ st_volume_t volume = _musicMuted ? 0 : _musicVolTable[_musicVol];
+
+ fpMus.seek(_music[i]._filePos, SEEK_SET);
+ _converter->flow(_music[i], data, len, volume, volume);
+ }
+
+ // DipMusic();
}
-void Sound::fxServer(int16 *data, uint len) {
+int32 Sound::dipMusic(void) {
+ // disable this func for now
+ return RD_OK;
+
+/*
+ int32 len;
+ int32 readCursor, writeCursor;
+ int32 dwBytes1, dwBytes2;
+ int16 *sample;
+ int32 total = 0;
+ int32 i;
+ int32 status;
+ LPVOID lpv1, lpv2;
+ HRESULT hr = DS_OK;
+ LPDIRECTSOUNDBUFFER dsbMusic = NULL;
+
+ int32 currentMusicVol = musicVolTable[musicVol];
+ int32 minMusicVol;
+
+ // Find which music buffer is currently playing
+ for (i = 0; i<MAXMUS && !dsbMusic; i++)
+ {
+ if (musStreaming[i] && musFading[i] == 0)
+ dsbMusic = lpDsbMus[i];
+ }
+
+ if ((!_musicMuted) && dsbMusic && (!_speechMuted) && (musicVol>2))
+ {
+ minMusicVol = musicVolTable[musicVol - 3];
+
+ if (_speechStatus)
+ {
+ IDirectSoundBuffer_GetStatus(dsbSpeech, &status);
+ if ((hr = IDirectSoundBuffer_GetCurrentPosition(dsbMusic, &readCursor, &writeCursor)) != DS_OK)
+ return hr;
+
+ len = 44100 / 12 ;// 12th of a second
+
+ if ((hr = IDirectSoundBuffer_Lock(dsbMusic, readCursor, len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0)) != DS_OK)
+ return hr;
+
+ for (i = 0, sample = (int16*)lpv1; sample<(int16*)((int8*)lpv1+dwBytes1); sample+= 30, i++) // 60 samples
+ {
+ if (*sample>0)
+ total += *sample;
+ else
+ total -= *sample;
+ }
+
+ total /= i;
+
+ total = minMusicVol + ( ( (currentMusicVol - minMusicVol) * total ) / 8000);
+
+ if (total > currentMusicVol)
+ total = currentMusicVol;
+
+ IDirectSoundBuffer_SetVolume(dsbMusic, total);
+
+ IDirectSoundBuffer_Unlock(dsbMusic,lpv1,dwBytes1,lpv2,dwBytes2);
+ }
+ else
+ {
+ IDirectSoundBuffer_GetVolume(dsbMusic, &total);
+ total += 50;
+ if (total > currentMusicVol)
+ total = currentMusicVol;
+
+ IDirectSoundBuffer_SetVolume(dsbMusic, total);
+ }
+ }
+
+ return hr;
+*/
+}
+
+/**
+ * @return the time left for the current music, in seconds.
+ */
+
+int32 Sound::musicTimeRemaining(void) {
Common::StackLock lock(_mutex);
+ for (int i = 0; i < MAXMUS; i++) {
+ if (_music[i]._streaming && _music[i]._fading <= 0)
+ return (_music[i]._fileEnd - _music[i]._filePos) / _music[i].getRate();
+ }
+
+ return 0;
+}
+
+// ----------------------------------------------------------------------------
+// SPEECH
+// ----------------------------------------------------------------------------
+
+/**
+ * Mutes/Unmutes the speech.
+ * @param mute If mute is false, restore the volume to the last set master
+ * level. Otherwise the speech is muted (volume 0).
+ */
+
+void Sound::muteSpeech(bool mute) {
+ _speechMuted = mute;
+
+ if (getSpeechStatus() == RDSE_SAMPLEPLAYING) {
+ byte volume = mute ? 0 : 16 * _speechVol;
+
+ _vm->_mixer->setChannelVolume(_soundHandleSpeech, volume);
+ }
+}
+
+/**
+ * @return the speech's mute state, true if mute, false if not mute
+ */
+
+bool Sound::isSpeechMute(void) {
+ return _speechMuted;
+}
+
+/**
+ * Set the volume of any future as well as playing speech samples.
+ * @param volume volume, from 0 (silent) to 14 (max)
+ */
+
+void Sound::setSpeechVolume(uint8 volume) {
+ if (volume > 14)
+ volume = 14;
+
+ _speechVol = volume;
+
+ if (_soundHandleSpeech.isActive() && !_speechMuted && getSpeechStatus() == RDSE_SAMPLEPLAYING) {
+ _vm->_mixer->setChannelVolume(_soundHandleSpeech, 16 * _speechVol);
+ }
+}
+
+/**
+ * @return the volume setting for speech
+ */
+
+uint8 Sound::getSpeechVolume(void) {
+ return _speechVol;
+}
+
+/**
+ * Stops the speech dead in its tracks.
+ */
+
+void Sound::pauseSpeech(void) {
+ if (getSpeechStatus() == RDSE_SAMPLEPLAYING) {
+ _speechPaused = true;
+ _vm->_mixer->pauseHandle(_soundHandleSpeech, true);
+ }
+}
+
+/**
+ * Restarts the speech from where it was stopped.
+ */
+
+void Sound::unpauseSpeech(void) {
+ if (_speechPaused) {
+ _speechPaused = false;
+ _vm->_mixer->pauseHandle(_soundHandleSpeech, false);
+ }
+}
+
+/**
+ * Stops the speech from playing.
+ */
+
+int32 Sound::stopSpeech(void) {
if (!_soundOn)
- return;
+ return RD_OK;
+
+ if (_speechStatus) {
+ _vm->_mixer->stopHandle(_soundHandleSpeech);
+ _speechStatus = false;
+ return RD_OK;
+ }
+ return RDERR_SPEECHNOTPLAYING;
+}
- updateCompSampleStreaming(data, len);
+/**
+ * @return Either RDSE_SAMPLEPLAYING or RDSE_SAMPLEFINISHED
+ */
- if (!_music[0]._streaming && !_music[1]._streaming && fpMus.isOpen())
- fpMus.close();
+int32 Sound::getSpeechStatus(void) {
+ if (!_soundOn || !_speechStatus)
+ return RDSE_SAMPLEFINISHED;
+
+ if (_speechPaused)
+ return RDSE_SAMPLEPLAYING;
+
+ if (!_soundHandleSpeech.isActive()) {
+ _speechStatus = false;
+ return RDSE_SAMPLEFINISHED;
+ }
+ return RDSE_SAMPLEPLAYING;
}
/**
* Returns either RDSE_QUIET or RDSE_SPEAKING
*/
-int32 Sound::amISpeaking() {
+int32 Sound::amISpeaking(void) {
if (!_speechMuted && !_speechPaused && _soundHandleSpeech.isActive())
return RDSE_SPEAKING;
@@ -391,324 +769,116 @@ uint32 Sound::preFetchCompSpeech(const char *filename, uint32 speechid, uint16 *
*/
int32 Sound::playCompSpeech(const char *filename, uint32 speechid, uint8 vol, int8 pan) {
+ if (_speechMuted)
+ return RD_OK;
+
uint16 *data16;
uint32 bufferSize;
- if (!_speechMuted) {
- if (getSpeechStatus() == RDERR_SPEECHPLAYING)
- return RDERR_SPEECHPLAYING;
+ if (getSpeechStatus() == RDERR_SPEECHPLAYING)
+ return RDERR_SPEECHPLAYING;
- bufferSize = preFetchCompSpeech(filename, speechid, &data16);
+ bufferSize = preFetchCompSpeech(filename, speechid, &data16);
- // We don't know exactly what went wrong here.
- if (bufferSize == 0)
- return RDERR_OUTOFMEMORY;
+ // We don't know exactly what went wrong here.
+ if (bufferSize == 0)
+ return RDERR_OUTOFMEMORY;
- // Modify the volume according to the master volume
+ // Modify the volume according to the master volume
- byte volume = _speechMuted ? 0 : vol * _speechVol;
- int8 p = _panTable[pan + 16];
+ byte volume = _speechMuted ? 0 : vol * _speechVol;
+ int8 p = _panTable[pan + 16];
- // Start the speech playing
+ // Start the speech playing
- _speechPaused = true;
+ _speechPaused = true;
- uint32 flags = SoundMixer::FLAG_16BITS | SoundMixer::FLAG_AUTOFREE;
+ uint32 flags = SoundMixer::FLAG_16BITS | SoundMixer::FLAG_AUTOFREE;
#ifndef SCUMM_BIG_ENDIAN
- flags |= SoundMixer::FLAG_LITTLE_ENDIAN;
+ flags |= SoundMixer::FLAG_LITTLE_ENDIAN;
#endif
- _vm->_mixer->playRaw(&_soundHandleSpeech, data16, bufferSize, 22050, flags, -1, volume, p);
+ _vm->_mixer->playRaw(&_soundHandleSpeech, data16, bufferSize, 22050, flags, -1, volume, p);
- _speechStatus = true;
- }
+ _speechStatus = true;
// DipMusic();
return RD_OK;
}
-/**
- * Stops the speech from playing.
- */
-
-int32 Sound::stopSpeech(void) {
- if (!_soundOn)
- return RD_OK;
-
- if (_speechStatus) {
- _vm->_mixer->stopHandle(_soundHandleSpeech);
- _speechStatus = false;
- return RD_OK;
- }
- return RDERR_SPEECHNOTPLAYING;
-}
-
-/**
- * @return Either RDSE_SAMPLEPLAYING or RDSE_SAMPLEFINISHED
- */
-
-int32 Sound::getSpeechStatus(void) {
- if (!_soundOn || !_speechStatus)
- return RDSE_SAMPLEFINISHED;
-
- if (_speechPaused)
- return RDSE_SAMPLEPLAYING;
-
- if (!_soundHandleSpeech.isActive()) {
- _speechStatus = false;
- return RDSE_SAMPLEFINISHED;
- }
- return RDSE_SAMPLEPLAYING;
-}
+// ----------------------------------------------------------------------------
+// SOUND EFFECTS
+// ----------------------------------------------------------------------------
/**
- * Set the volume of any future as well as playing speech samples.
- * @param volume volume, from 0 (silent) to 14 (max)
+ * @return the index of the sound effect with the ID passed in.
*/
-void Sound::setSpeechVolume(uint8 volume) {
- if (volume > 14)
- volume = 14;
-
- _speechVol = volume;
-
- if (_soundHandleSpeech.isActive() && !_speechMuted && getSpeechStatus() == RDSE_SAMPLEPLAYING) {
- _vm->_mixer->setChannelVolume(_soundHandleSpeech, 16 * _speechVol);
+int32 Sound::getFxIndex(int32 id) {
+ for (int i = 0; i < MAXFX; i++) {
+ if (_fx[i]._id == id)
+ return i;
}
-}
-
-/**
- * @return the volume setting for speech
- */
-uint8 Sound::getSpeechVolume() {
- return _speechVol;
+ return MAXFX;
}
/**
- * Mutes/Unmutes the speech.
+ * Mutes/Unmutes the sound effects.
* @param mute If mute is false, restore the volume to the last set master
- * level. Otherwise the speech is muted (volume 0).
- */
-
-void Sound::muteSpeech(bool mute) {
- _speechMuted = mute;
-
- if (getSpeechStatus() == RDSE_SAMPLEPLAYING) {
- byte volume = mute ? 0 : 16 * _speechVol;
-
- _vm->_mixer->setChannelVolume(_soundHandleSpeech, volume);
- }
-}
-
-/**
- * @return the speech's mute state, true if mute, false if not mute
+ * level. Otherwise the sound effects are muted (volume 0).
*/
-bool Sound::isSpeechMute(void) {
- return _speechMuted;
-}
+void Sound::muteFx(bool mute) {
+ _fxMuted = mute;
-/**
- * Stops the speech dead in its tracks.
- */
+ // Now update the volume of any fxs playing
+ for (int i = 0; i < MAXFX; i++) {
+ if (_fx[i]._id) {
+ byte volume = mute ? 0 : _fx[i]._volume * _fxVol;
-void Sound::pauseSpeech(void) {
- if (getSpeechStatus() == RDSE_SAMPLEPLAYING) {
- _speechPaused = true;
- _vm->_mixer->pauseHandle(_soundHandleSpeech, true);
+ _vm->_mixer->setChannelVolume(_fx[i]._handle, volume);
+ }
}
}
/**
- * Restarts the speech from where it was stopped.
+ * @return the sound effects's mute state, true if mute, false if not mute
*/
-void Sound::unpauseSpeech(void) {
- if (_speechPaused) {
- _speechPaused = false;
- _vm->_mixer->pauseHandle(_soundHandleSpeech, false);
- }
+bool Sound::isFxMute(void) {
+ return _fxMuted;
}
/**
- * This function opens a sound effect ready for playing. A unique id should be
- * passed in so that each effect can be referenced individually.
- * @param id the unique sound id
- * @param data the WAV data
- * @warning Zero is not a valid id
+ * @return the master volume setting for sound effects
*/
-int32 Sound::openFx(int32 id, uint8 *data) {
- int32 i, fxi;
- uint32 *data32 = NULL;
- WavHeader *wav;
-
- wav = (WavHeader *) data;
-
- if (_soundOn) {
- // Check for a valid id.
- if (id == 0)
- return RDERR_INVALIDID;
-
- // Check that the fx is not already open
- for (i = 0; i < MAXFX; i++) {
- if (_fx[i]._id == id)
- return RDERR_FXALREADYOPEN;
- }
-
- // Now choose a free slot for the fx
- for (fxi = 0; fxi < MAXFX; fxi++) {
- if (_fx[fxi]._id == 0)
- break;
- }
-
- if (fxi == MAXFX) {
- // Expire the first sound effect that isn't currently
- // playing. This usually shouldn't happen since the
- // game engine manually clears all sound effects (at
- // least except for lead-ins and lead-outs) when moving
- // between rooms.
-
- for (fxi = 0; fxi < MAXFX; fxi++) {
- if (!_fx[fxi]._handle.isActive())
- break;
- }
-
- // Still no dice? I give up!
-
- if (fxi == MAXFX) {
- warning("openFx: No free sound slots");
- return RDERR_NOFREEBUFFERS;
- }
- }
-
- // Set the sample size - search for the size of the data.
- i = 0;
- while (i < 100) {
- if (*data == 'd') {
- data32 = (uint32 *) data;
- if (READ_UINT32(data32) == MKID('data'))
- break;
- }
- i++;
- data++;
- }
-
- if (!data32)
- return RDERR_INVALIDWAV;
-
- _fx[fxi]._bufSize = READ_LE_UINT32(data32 + 1);
-
- // Fill the speech buffer with data
- if (_fx[fxi]._buf != NULL)
- free(_fx[fxi]._buf);
- _fx[fxi]._buf = (uint16 *) malloc(_fx[fxi]._bufSize);
- memcpy(_fx[fxi]._buf, (uint8 *) (data32 + 2), _fx[fxi]._bufSize);
- _fx[fxi]._flags = SoundMixer::FLAG_16BITS | SoundMixer::FLAG_LITTLE_ENDIAN;
- if (FROM_LE_16(wav->channels) == 2)
- _fx[fxi]._flags |= SoundMixer::FLAG_STEREO;
-
- _fx[fxi]._rate = FROM_LE_16(wav->samplesPerSec);
- _fx[fxi]._id = id;
- }
- return RD_OK;
+uint8 Sound::getFxVolume(void) {
+ return _fxVol;
}
/**
- * This function plays a sound effect. If the effect has already been opened
- * then 'data' should be NULL, and the sound effect will simply be obtained
- * from the id passed in. If the effect has not been opened, then the WAV data
- * should be passed in 'data'. The sound effect will be closed when it has
- * finished playing.
- * @param id the sound id
- * @param data either NULL or the WAV data
- * @param vol volume, 0 (minimum) to 16 (maximum)
- * @param pan panning, -16 (full left) to 16 (full right)
- * @param type either RDSE_FXSPOT or RDSE_FXLOOP
- * @warning Zero is not a valid id
+ * Set the master volume of all sound effects. The effects still have their
+ * own volume setting as well as the master volume.
+ * @param volume volume, from 0 (silent) to 14 (max)
*/
-int32 Sound::playFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type) {
- int32 i, loop;
- uint32 hr;
-
- if (type == RDSE_FXLOOP)
- loop = 1;
- else
- loop = 0;
-
- if (_soundOn) {
- if (data == NULL) {
- i = getFxIndex(id);
- if (i == MAXFX) {
- warning("playFx(%d, %d, %d, %d) - Not open", id, vol, pan, type);
- return RDERR_FXNOTOPEN;
- }
- if (loop == 1)
- _fx[i]._flags |= SoundMixer::FLAG_LOOP;
- else
- _fx[i]._flags &= ~SoundMixer::FLAG_LOOP;
-
- _fx[i]._volume = vol;
-
- // Start the sound effect playing
+void Sound::setFxVolume(uint8 volume) {
+ if (volume > 14)
+ volume = 14;
- byte volume = _fxMuted ? 0 : vol * _fxVol;
- int8 p = _panTable[pan + 16];
+ _fxVol = volume;
- _vm->_mixer->playRaw(&_fx[i]._handle, _fx[i]._buf, _fx[i]._bufSize, _fx[i]._rate, _fx[i]._flags, -1, volume, p);
- } else {
- if (type == RDSE_FXLEADIN || type == RDSE_FXLEADOUT) {
- if (type == RDSE_FXLEADIN)
- id = -2;
- else
- id = -1;
-
- hr = openFx(id, data);
- if (hr != RD_OK)
- return hr;
-
- i = getFxIndex(id);
- if (i == MAXFX) {
- warning("playFx(%d, %d, %d, %d) - Not found", id, vol, pan, type);
- return RDERR_FXFUCKED;
- }
- _fx[i]._flags &= ~SoundMixer::FLAG_LOOP;
-
- byte volume = _musicMuted ? 0 : musicVolTable[_musicVol];
-
- _vm->_mixer->playRaw(&_fx[i]._handle, _fx[i]._buf, _fx[i]._bufSize, _fx[i]._rate, _fx[i]._flags, -1, volume, 0);
- } else {
- hr = openFx(id, data);
- if (hr != RD_OK) {
- return hr;
- }
-
- i = getFxIndex(id);
- if (i == MAXFX) {
- warning("playFx(%d, %d, %d, %d) - Not found", id, vol, pan, type);
- return RDERR_FXFUCKED;
- }
- if (loop == 1)
- _fx[i]._flags |= SoundMixer::FLAG_LOOP;
- else
- _fx[i]._flags &= ~SoundMixer::FLAG_LOOP;
- _fx[i]._volume = vol;
-
- // Start the sound effect playing
-
- byte volume = _fxMuted ? 0 : vol * _fxVol;
- int8 p = _panTable[pan + 16];
-
- _vm->_mixer->playRaw(&_fx[i]._handle, _fx[i]._buf, _fx[i]._bufSize, _fx[i]._rate, _fx[i]._flags, -1, volume, p);
- }
- }
- }
+ if (_fxMuted)
+ return;
- return RD_OK;
+ // Now update the volume of any fxs playing
+ for (int i = 0; i < MAXFX; i++)
+ if (_fx[i]._id)
+ _vm->_mixer->setChannelVolume(_fx[i]._handle, _fx[i]._volume * _fxVol);
}
/**
@@ -744,419 +914,241 @@ int32 Sound::setFxIdVolume(int32 id, uint8 vol) {
return RDERR_FXNOTOPEN;
_fx[i]._volume = vol;
+
if (!_fxMuted)
_vm->_mixer->setChannelVolume(_fx[i]._handle, vol * _fxVol);
return RD_OK;
}
-/**
- * This function clears all of the sound effects which are currently open or
- * playing, irrespective of type.
- */
-void Sound::clearAllFx(void) {
- if (!_soundOn)
+void Sound::pauseFx(void) {
+ if (_fxPaused)
return;
for (int i = 0; i < MAXFX; i++) {
- if (_fx[i]._id && _fx[i]._id != -1 && _fx[i]._id != -2) {
- _vm->_mixer->stopHandle(_fx[i]._handle);
- _fx[i]._id = 0;
+ if (_fx[i]._id) {
+ _vm->_mixer->pauseHandle(_fx[i]._handle, true);
+ _fx[i]._paused = true;
+ } else
_fx[i]._paused = false;
- if (_fx[i]._buf != NULL) {
- free(_fx[i]._buf);
- _fx[i]._buf = NULL;
- }
- _fx[i]._bufSize = 0;
- _fx[i]._flags = 0;
- }
- }
-}
-
-/**
- * This function closes a sound effect which has been previously opened for
- * playing. Sound effects must be closed when they are finished with, otherwise
- * you will run out of sound effect buffers.
- * @param id the id of the sound to close
- */
-
-int32 Sound::closeFx(int32 id) {
- int i;
-
- if (!_soundOn)
- return RD_OK;
-
- i = getFxIndex(id);
-
- if (i == MAXFX)
- return RDERR_FXNOTOPEN;
-
- _vm->_mixer->stopHandle(_fx[i]._handle);
- _fx[i]._id = 0;
- _fx[i]._paused = false;
- if (_fx[i]._buf != NULL) {
- free(_fx[i]._buf);
- _fx[i]._buf = NULL;
}
- _fx[i]._bufSize = 0;
- _fx[i]._flags = 0;
- return RD_OK;
-}
-
-void Sound::pauseFx(void) {
- if (!_fxPaused) {
- for (int i = 0; i < MAXFX; i++) {
- if (_fx[i]._id) {
- _vm->_mixer->pauseHandle(_fx[i]._handle, true);
- _fx[i]._paused = true;
- } else
- _fx[i]._paused = false;
- }
- _fxPaused = true;
- }
+ _fxPaused = true;
}
void Sound::pauseFxForSequence(void) {
- if (!_fxPaused) {
- for (int i = 0; i < MAXFX; i++) {
- if (_fx[i]._id && _fx[i]._id != -2) {
- _vm->_mixer->pauseHandle(_fx[i]._handle, true);
- _fx[i]._paused = true;
- } else {
- _fx[i]._paused = false;
- }
- }
- _fxPaused = true;
- }
-}
+ if (_fxPaused)
+ return;
-void Sound::unpauseFx(void) {
- if (_fxPaused) {
- for (int i = 0; i < MAXFX; i++) {
- if (_fx[i]._paused && _fx[i]._id) {
- _vm->_mixer->pauseHandle(_fx[i]._handle, false);
- }
- }
- _fxPaused = false;
+ for (int i = 0; i < MAXFX; i++) {
+ if (_fx[i]._id && _fx[i]._id != -2) {
+ _vm->_mixer->pauseHandle(_fx[i]._handle, true);
+ _fx[i]._paused = true;
+ } else
+ _fx[i]._paused = false;
}
-}
-/**
- * @return the master volume setting for sound effects
- */
-
-uint8 Sound::getFxVolume() {
- return _fxVol;
+ _fxPaused = true;
}
-/**
- * Set the master volume of all sound effects. The effects still have their
- * own volume setting as well as the master volume.
- * @param volume volume, from 0 (silent) to 14 (max)
- */
-
-void Sound::setFxVolume(uint8 volume) {
- if (volume > 14)
- volume = 14;
+void Sound::unpauseFx(void) {
+ if (!_fxPaused)
+ return;
- _fxVol = volume;
+ for (int i = 0; i < MAXFX; i++)
+ if (_fx[i]._paused && _fx[i]._id)
+ _vm->_mixer->pauseHandle(_fx[i]._handle, false);
- // Now update the volume of any fxs playing
- for (int i = 0; i < MAXFX; i++) {
- if (_fx[i]._id && !_fxMuted)
- _vm->_mixer->setChannelVolume(_fx[i]._handle, _fx[i]._volume * _fxVol);
- }
+ _fxPaused = false;
}
-/**
- * Mutes/Unmutes the sound effects.
- * @param mute If mute is false, restore the volume to the last set master
- * level. Otherwise the sound effects are muted (volume 0).
- */
-
-void Sound::muteFx(bool mute) {
- _fxMuted = mute;
-
- // Now update the volume of any fxs playing
- for (int i = 0; i < MAXFX; i++) {
- if (_fx[i]._id) {
- byte volume = mute ? 0 : _fx[i]._volume * _fxVol;
-
- _vm->_mixer->setChannelVolume(_fx[i]._handle, volume);
- }
- }
-}
+bool Sound::isFxPlaying(int32 id) {
+ int i;
-/**
- * @return the sound effects's mute state, true if mute, false if not mute
- */
+ i = getFxIndex(id);
+ if (i == MAXFX)
+ return false;
-bool Sound::isFxMute(void) {
- return _fxMuted;
+ return _fx[i]._handle.isActive();
}
/**
- * Streams music from a cluster file.
- * @param filename the file name of the music cluster file
- * @param musicId the id of the music to stream
- * @param looping true if the music is to loop back to the start
- * @return RD_OK or an error code
+ * This function opens a sound effect ready for playing. A unique id should be
+ * passed in so that each effect can be referenced individually.
+ * @param id the unique sound id
+ * @param data the WAV data
+ * @warning Zero is not a valid id
*/
-int32 Sound::streamCompMusic(const char *filename, uint32 musicId, bool looping) {
- Common::StackLock lock(_mutex);
-
- uint32 len;
- int32 primaryStream = -1;
- int32 secondaryStream = -1;
-
- // If both music streams are playing, that should mean one of them is
- // fading out. Pick that one.
-
- if (_music[0]._streaming && _music[1]._streaming) {
- if (_music[0]._fading)
- primaryStream = 0;
- else
- primaryStream = 1;
-
- _music[primaryStream]._fading = 0;
- _music[primaryStream]._streaming = false;
- }
-
- // Pick the available music stream. If no music is playing it doesn't
- // matter which we use, so pick the first one.
-
- if (_music[0]._streaming || _music[1]._streaming) {
- if (_music[0]._streaming) {
- primaryStream = 1;
- secondaryStream = 0;
- } else {
- primaryStream = 0;
- secondaryStream = 1;
- }
- } else
- primaryStream = 0;
-
- // Save looping info and tune id
- _music[primaryStream]._looping = looping;
- _music[primaryStream]._id = musicId;
-
- // Don't start streaming if the volume is off.
- if (isMusicMute())
+int32 Sound::openFx(int32 id, uint8 *data) {
+ if (!_soundOn)
return RD_OK;
- // The assumption here is that we are never playing music from two
- // different files at the same time.
-
- if (!fpMus.isOpen())
- fpMus.open(filename);
-
- if (!fpMus.isOpen())
- return RDERR_INVALIDFILENAME;
-
- // Start other music stream fading out
- if (secondaryStream != -1 && !_music[secondaryStream]._fading)
- _music[secondaryStream]._fading = FADE_SAMPLES;
-
- fpMus.seek((musicId + 1) * 8, SEEK_SET);
- _music[primaryStream]._fileStart = fpMus.readUint32LE();
- len = fpMus.readUint32LE();
-
- if (!_music[primaryStream]._fileStart || !len)
+ if (id == 0)
return RDERR_INVALIDID;
- _music[primaryStream]._fileEnd = _music[primaryStream]._fileStart + len;
- _music[primaryStream]._filePos = _music[primaryStream]._fileStart;
- _music[primaryStream]._streaming = true;
- _music[primaryStream]._firstTime = true;
-
- return RD_OK;
-}
-
-void Sound::updateCompSampleStreaming(int16 *data, uint len) {
- for (int i = 0; i < MAXMUS; i++) {
- if (!_music[i]._streaming || _music[i]._paused)
- continue;
-
- st_volume_t volume = _musicMuted ? 0 : musicVolTable[_musicVol];
+ if (getFxIndex(id) != MAXFX)
+ return RDERR_FXALREADYOPEN;
- fpMus.seek(_music[i]._filePos, SEEK_SET);
- _converter->flow(_music[i], data, len, volume, volume);
- }
+ // Find a free slot
+ int32 fxi = getFxIndex(0);
- // DipMusic();
-}
+ if (fxi == MAXFX) {
+ warning("openFx: Running out of sound slots");
-int32 Sound::dipMusic() {
- // disable this func for now
- return RD_OK;
+ // There isn't any free sound handle available. This usually
+ // shouldn't happen, but if it does we expire the first sound
+ // effect that isn't currently playing.
-/*
- int32 len;
- int32 readCursor, writeCursor;
- int32 dwBytes1, dwBytes2;
- int16 *sample;
- int32 total = 0;
- int32 i;
- int32 status;
- LPVOID lpv1, lpv2;
- HRESULT hr = DS_OK;
- LPDIRECTSOUNDBUFFER dsbMusic = NULL;
+ for (fxi = 0; fxi < MAXFX; fxi++)
+ if (!_fx[fxi]._handle.isActive())
+ break;
- int32 currentMusicVol = musicVolTable[musicVol];
- int32 minMusicVol;
+ // Still no dice? I give up!
- // Find which music buffer is currently playing
- for (i = 0; i<MAXMUS && !dsbMusic; i++)
- {
- if (musStreaming[i] && musFading[i] == 0)
- dsbMusic = lpDsbMus[i];
+ if (fxi == MAXFX) {
+ warning("openFx: No free sound slots");
+ return RDERR_NOFREEBUFFERS;
+ }
}
- if ((!_musicMuted) && dsbMusic && (!_speechMuted) && (musicVol>2))
- {
- minMusicVol = musicVolTable[musicVol - 3];
+ if (READ_UINT32(data) != MKID('RIFF') || READ_UINT32(data + 8) != MKID('WAVE') || READ_UINT32(data + 12) != MKID('fmt ')) {
+ warning("openFx: Not a valid WAV file");
+ return RDERR_INVALIDWAV;
+ }
- if (_speechStatus)
- {
- IDirectSoundBuffer_GetStatus(dsbSpeech, &status);
- if ((hr = IDirectSoundBuffer_GetCurrentPosition(dsbMusic, &readCursor, &writeCursor)) != DS_OK)
- return hr;
+ _fx[fxi]._id = id;
+ _fx[fxi]._flags = SoundMixer::FLAG_16BITS | SoundMixer::FLAG_LITTLE_ENDIAN;
- len = 44100 / 12 ;// 12th of a second
+ if (READ_LE_UINT16(data + 22) == 2)
+ _fx[fxi]._flags |= SoundMixer::FLAG_STEREO;
- if ((hr = IDirectSoundBuffer_Lock(dsbMusic, readCursor, len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0)) != DS_OK)
- return hr;
+ _fx[fxi]._rate = READ_LE_UINT16(data + 24);
- for (i = 0, sample = (int16*)lpv1; sample<(int16*)((int8*)lpv1+dwBytes1); sample+= 30, i++) // 60 samples
- {
- if (*sample>0)
- total += *sample;
- else
- total -= *sample;
- }
-
- total /= i;
-
- total = minMusicVol + ( ( (currentMusicVol - minMusicVol) * total ) / 8000);
+ data += READ_UINT32(data + 16) + 20;
- if (total > currentMusicVol)
- total = currentMusicVol;
+ if (READ_UINT32(data) != MKID('data')) {
+ warning("openFx: WAV file has no 'data' chunk");
+ return RDERR_INVALIDWAV;
+ }
- IDirectSoundBuffer_SetVolume(dsbMusic, total);
+ _fx[fxi]._bufSize = READ_LE_UINT32(data + 4);
- IDirectSoundBuffer_Unlock(dsbMusic,lpv1,dwBytes1,lpv2,dwBytes2);
- }
- else
- {
- IDirectSoundBuffer_GetVolume(dsbMusic, &total);
- total += 50;
- if (total > currentMusicVol)
- total = currentMusicVol;
+ // Fill the speech buffer with data
+ free(_fx[fxi]._buf);
+ _fx[fxi]._buf = (uint16 *) malloc(_fx[fxi]._bufSize);
+ memcpy(_fx[fxi]._buf, data + 8, _fx[fxi]._bufSize);
- IDirectSoundBuffer_SetVolume(dsbMusic, total);
- }
- }
-
- return hr;
-*/
+ return RD_OK;
}
/**
- * @return the time left for the current music, in seconds.
+ * This function closes a sound effect which has been previously opened for
+ * playing. Sound effects must be closed when they are finished with, otherwise
+ * you will run out of sound effect buffers.
+ * @param id the id of the sound to close
*/
-int32 Sound::musicTimeRemaining() {
- Common::StackLock lock(_mutex);
-
- for (int i = 0; i < MAXMUS; i++) {
- if (_music[i]._streaming && !_music[i]._fading)
- return (_music[i]._fileEnd - _music[i]._filePos) / 22050;
- }
+int32 Sound::closeFx(int32 id) {
+ int i;
- return 0;
-}
+ if (!_soundOn)
+ return RD_OK;
-/**
- * Fades out and stops the music.
- */
+ i = getFxIndex(id);
-void Sound::stopMusic(void) {
- Common::StackLock lock(_mutex);
+ if (i == MAXFX)
+ return RDERR_FXNOTOPEN;
- for (int i = 0; i < MAXMUS; i++) {
- if (_music[i]._streaming)
- _music[i]._fading = FADE_SAMPLES;
- else
- _music[i]._looping = false;
- }
+ stopFxHandle(i);
+ return RD_OK;
}
/**
- * Stops the music dead in its tracks. Any music that is currently being
- * streamed is paued.
+ * This function plays a sound effect. If the effect has already been opened
+ * then 'data' should be NULL, and the sound effect will simply be obtained
+ * from the id passed in. If the effect has not been opened, then the WAV data
+ * should be passed in 'data'. The sound effect will be closed when it has
+ * finished playing.
+ * @param id the sound id
+ * @param data either NULL or the WAV data
+ * @param vol volume, 0 (minimum) to 16 (maximum)
+ * @param pan panning, -16 (full left) to 16 (full right)
+ * @param type either RDSE_FXSPOT or RDSE_FXLOOP
+ * @warning Zero is not a valid id
*/
-void Sound::pauseMusic(void) {
- Common::StackLock lock(_mutex);
+int32 Sound::playFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type) {
+ if (!_soundOn)
+ return RD_OK;
- if (_soundOn) {
- for (int i = 0; i < MAXMUS; i++)
- _music[i]._paused = _music[i]._streaming;
- }
-}
+ byte volume = _fxMuted ? 0 : vol * _fxVol;
+ int8 p = _panTable[pan + 16];
+ int32 i, hr;
-/**
- * Restarts the music from where it was stopped.
- */
+ if (data) {
+ // All lead-ins and lead-outs I've heard are music, so we use
+ // the music volume setting for them.
-void Sound::unpauseMusic(void) {
- Common::StackLock lock(_mutex);
+ if (type == RDSE_FXLEADIN || type == RDSE_FXLEADOUT) {
+ id = (type == RDSE_FXLEADIN) ? -2 : -1;
+ volume = _musicMuted ? 0 : _musicVolTable[_musicVol];
+ }
- if (_soundOn) {
- for (int i = 0; i < MAXMUS; i++)
- _music[i]._paused = false;
+ hr = openFx(id, data);
+ if (hr != RD_OK)
+ return hr;
}
-}
-/**
- * Set the volume of any future as well as playing music.
- * @param volume volume, from 0 (silent) to 16 (max)
- */
+ i = getFxIndex(id);
-void Sound::setMusicVolume(uint8 volume) {
- if (volume > 16)
- volume = 16;
+ if (i == MAXFX) {
+ if (data) {
+ warning("playFx(%d, %d, %d, %d) - Not found", id, vol, pan, type);
+ return RDERR_FXFUCKED;
+ } else {
+ warning("playFx(%d, %d, %d, %d) - Not open", id, vol, pan, type);
+ return RDERR_FXNOTOPEN;
+ }
+ }
- _musicVol = volume;
-}
+ if (type == RDSE_FXLOOP)
+ _fx[i]._flags |= SoundMixer::FLAG_LOOP;
+ else
+ _fx[i]._flags &= ~SoundMixer::FLAG_LOOP;
-/**
- * @return the volume setting for music
- */
+ _fx[i]._volume = vol;
-uint8 Sound::getMusicVolume() {
- return _musicVol;
-}
+ _vm->_mixer->playRaw(&_fx[i]._handle, _fx[i]._buf, _fx[i]._bufSize, _fx[i]._rate, _fx[i]._flags, -1, volume, p);
-/**
- * Mutes/Unmutes the music.
- * @param mute If mute is false, restore the volume to the last set master
- * level. Otherwise the music is muted (volume 0).
- */
+ return RD_OK;
+}
-void Sound::muteMusic(bool mute) {
- _musicMuted = mute;
+void Sound::stopFxHandle(int i) {
+ if (_fx[i]._id) {
+ _vm->_mixer->stopHandle(_fx[i]._handle);
+ free(_fx[i]._buf);
+ _fx[i]._id = 0;
+ _fx[i]._paused = false;
+ _fx[i]._flags = 0;
+ _fx[i]._bufSize = 0;
+ _fx[i]._buf = NULL;
+ }
}
/**
- * @return the music's mute state, true if mute, false if not mute
+ * This function clears all of the sound effects which are currently open or
+ * playing, irrespective of type.
*/
-bool Sound::isMusicMute(void) {
- return _musicMuted;
+void Sound::clearAllFx(void) {
+ if (!_soundOn)
+ return;
+
+ for (int i = 0; i < MAXFX; i++)
+ if (_fx[i]._id && _fx[i]._id != -1 && _fx[i]._id != -2)
+ stopFxHandle(i);
}
} // End of namespace Sword2
diff --git a/sword2/driver/d_sound.h b/sword2/driver/d_sound.h
index 56580fc561..2e2899e921 100644
--- a/sword2/driver/d_sound.h
+++ b/sword2/driver/d_sound.h
@@ -46,7 +46,6 @@ struct FxHandle {
class MusicHandle : public AudioInputStream {
public:
- uint32 _id;
bool _firstTime;
bool _streaming;
bool _paused;
@@ -57,26 +56,22 @@ public:
int32 _fileEnd;
uint16 _lastSample;
- bool isStereo() const { return false; }
- int getRate() const { return 22050; }
+ bool isStereo(void) const { return false; }
+ int getRate(void) const { return 22050; }
- virtual int readBuffer(int16 *buffer, const int numSamples) {
- int samples;
- for (samples = 0; samples < numSamples && !endOfData(); samples++) {
- *buffer++ = read();
- }
- return samples;
- }
-
- int16 read();
- bool endOfData() const;
+ void fadeDown(void);
+ void fadeUp(void);
+ int32 play(const char *filename, uint32 musicId, bool looping);
+ void stop(void);
+ virtual int readBuffer(int16 *buffer, const int numSamples);
+ int16 read(void);
+ bool endOfData(void) const;
// This stream never 'ends'
- bool endOfStream() const { return false; }
+ bool endOfStream(void) const { return false; }
- MusicHandle() : _firstTime(false),
- _streaming(false), _paused(false), _looping(false),
- _fading(0), _fileStart(0), _filePos(0), _fileEnd(0),
- _lastSample(0) {}
+ MusicHandle() : _firstTime(false), _streaming(false), _paused(false),
+ _looping(false), _fading(0), _fileStart(0),
+ _filePos(0), _fileEnd(0), _lastSample(0) {}
};
class Sound {
@@ -84,75 +79,80 @@ private:
Sword2Engine *_vm;
OSystem::MutexRef _mutex;
- RateConverter *_converter;
int32 _panTable[33];
+ bool _soundOn;
- FxHandle _fx[MAXFX];
+ static int32 _musicVolTable[17];
MusicHandle _music[MAXMUS + 1];
+ char *savedMusicFilename;
+ RateConverter *_converter;
+ bool _musicMuted;
+ uint8 _musicVol;
- bool _soundOn;
+ void updateCompSampleStreaming(int16 *data, uint len);
+ int32 dipMusic(void);
+
+ PlayingSoundHandle _soundHandleSpeech;
bool _speechStatus;
bool _speechPaused;
- bool _fxPaused;
- bool _musicMuted;
bool _speechMuted;
- bool _fxMuted;
- uint8 _musicVol;
uint8 _speechVol;
- uint8 _fxVol;
- PlayingSoundHandle _soundHandleSpeech;
+ FxHandle _fx[MAXFX];
+ bool _fxPaused;
+ bool _fxMuted;
+ uint8 _fxVol;
int32 getFxIndex(int32 id);
- int32 dipMusic();
-
- void updateCompSampleStreaming(int16 *data, uint len);
-
- char *savedMusicFilename;
+ void stopFxHandle(int i);
public:
Sound(Sword2Engine *vm);
~Sound();
+
void fxServer(int16 *data, uint len);
- int32 playCompSpeech(const char *filename, uint32 speechid, uint8 vol, int8 pan);
- uint32 preFetchCompSpeech(const char *filename, uint32 speechid, uint16 **buf);
- int32 amISpeaking();
- int32 stopSpeech(void);
- int32 getSpeechStatus(void);
- void pauseSpeech(void);
- void unpauseSpeech(void);
- int32 openFx(int32 id, uint8 *data);
- int32 playFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type);
- int32 closeFx(int32 id);
- void clearAllFx(void);
- void pauseFx(void);
- void pauseFxForSequence(void);
- void unpauseFx(void);
+ void buildPanTable(bool reverse);
+
+ void muteMusic(bool mute);
+ bool isMusicMute(void);
+ void setMusicVolume(uint8 vol);
+ uint8 getMusicVolume(void);
void pauseMusic(void);
void unpauseMusic(void);
- int32 streamCompMusic(const char *filename, uint32 musicId, bool looping);
- void saveMusicState();
- void restoreMusicState();
+ void stopMusic(void);
+ void saveMusicState(void);
+ void restoreMusicState(void);
void playLeadOut(uint8 *leadOut);
- int32 musicTimeRemaining();
- void buildPanTable(bool reverse);
- uint8 getFxVolume(void);
- uint8 getSpeechVolume(void);
- uint8 getMusicVolume(void);
- bool isMusicMute(void);
- bool isFxMute(void);
+ int32 streamCompMusic(const char *filename, uint32 musicId, bool looping);
+ int32 musicTimeRemaining(void);
+
+ void muteSpeech(bool mute);
bool isSpeechMute(void);
- void stopMusic(void);
- void setFxVolume(uint8 vol);
void setSpeechVolume(uint8 vol);
- void setMusicVolume(uint8 vol);
- void muteMusic(bool mute);
+ uint8 getSpeechVolume(void);
+ void pauseSpeech(void);
+ void unpauseSpeech(void);
+ int32 stopSpeech(void);
+ int32 getSpeechStatus(void);
+ int32 amISpeaking(void);
+ uint32 preFetchCompSpeech(const char *filename, uint32 speechid, uint16 **buf);
+ int32 playCompSpeech(const char *filename, uint32 speechid, uint8 vol, int8 pan);
+
void muteFx(bool mute);
- void muteSpeech(bool mute);
- int32 isFxOpen(int32 id);
+ bool isFxMute(void);
+ uint8 getFxVolume(void);
+ void setFxVolume(uint8 vol);
int32 setFxIdVolumePan(int32 id, uint8 vol, int8 pan);
int32 setFxIdVolume(int32 id, uint8 vol);
+ void pauseFx(void);
+ void pauseFxForSequence(void);
+ void unpauseFx(void);
+ bool isFxPlaying(int32 id);
+ int32 openFx(int32 id, uint8 *data);
+ int32 closeFx(int32 id);
+ int32 playFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type);
+ void clearAllFx(void);
};
} // End of namespace Sword2
diff --git a/sword2/driver/driver96.h b/sword2/driver/driver96.h
index 8c836ccecf..2af4808e49 100644
--- a/sword2/driver/driver96.h
+++ b/sword2/driver/driver96.h
@@ -218,26 +218,6 @@ struct SpriteInfo {
uint8 *colourTable; // pointer to 16-byte colour table, only applicable to 16-col compression type
};
-// This is the format of a .WAV file. Somewhere after this header is the
-// string 'DATA' followed by an int32 size which is the size of the data.
-// Following the size of the data is the data itself.
-
-struct WavHeader {
- uint32 riff;
- uint32 fileLength;
- uint32 wavID;
- uint32 format;
- uint32 formatLen;
- uint16 formatTag;
- uint16 channels;
- uint16 samplesPerSec;
- uint16 avgBytesPerSec;
- uint16 blockAlign;
- uint16 unknown1;
- uint16 unknown2;
- uint16 bitsPerSample;
-};
-
// This is the structure which is passed to the sequence player. It includes
// the smack to play, and any text lines which are to be displayed over the top
// of the sequence.
diff --git a/sword2/sound.cpp b/sword2/sound.cpp
index 22061969d6..cf93f153f1 100644
--- a/sword2/sound.cpp
+++ b/sword2/sound.cpp
@@ -67,8 +67,10 @@ void Sword2Engine::processFxQueue(void) {
break;
case FX_SPOT2:
// Once the Fx has finished remove it from the queue.
- if (_sound->isFxOpen(i + 1))
+ if (!_sound->isFxPlaying(i + 1)) {
_fxQueue[i].resource = 0;
+ _sound->closeFx(i + 1);
+ }
break;
}
}
@@ -178,6 +180,7 @@ int32 Logic::fnPlayFx(int32 *params) {
break;
default:
strcpy(type, "INVALID");
+ break;
}
debug(0, "SFX (sample=\"%s\", vol=%d, pan=%d, delay=%d, type=%s)", _vm->fetchObjectName(params[0]), params[3], params[4], params[2], type);
@@ -244,7 +247,7 @@ int32 Logic::fnPlayFx(int32 *params) {
}
if (_vm->_fxQueue[j].type == FX_LOOP) {
- // play now, rather than in Process_fx_queue where it was
+ // play now, rather than in processFxQueue where it was
// getting played again & again!
_vm->triggerFx(j);
}