diff options
author | Torbjörn Andersson | 2004-01-03 11:24:39 +0000 |
---|---|---|
committer | Torbjörn Andersson | 2004-01-03 11:24:39 +0000 |
commit | bb8ff0cd904c89cf70c4419e068f5b0621799006 (patch) | |
tree | 289939f0447ed8af5ae9c17acd6058377b94be99 /sword2 | |
parent | e73363bd095005e9b849a50f97cd1a9ff04e5ba1 (diff) | |
download | scummvm-rg350-bb8ff0cd904c89cf70c4419e068f5b0621799006.tar.gz scummvm-rg350-bb8ff0cd904c89cf70c4419e068f5b0621799006.tar.bz2 scummvm-rg350-bb8ff0cd904c89cf70c4419e068f5b0621799006.zip |
Made the music code more like the one in BS1, i.e. the fade time is longer
and it now fades both up and down.
Plenty of cleanups, simplifications and just moving code around to group it
in what I hope is a more logical fashion.
Fixed a long-standing bug where spot effects would eventually use up all
available sound effect handles. (I may have introduced this when I removed
the expiration of sound effects from FxServer().)
svn-id: r12108
Diffstat (limited to 'sword2')
-rw-r--r-- | sword2/driver/d_sound.cpp | 1336 | ||||
-rw-r--r-- | sword2/driver/d_sound.h | 124 | ||||
-rw-r--r-- | sword2/driver/driver96.h | 20 | ||||
-rw-r--r-- | sword2/sound.cpp | 7 |
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); } |