mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-30 21:00:39 +00:00
Simplified the handling of sound effects. It's not necessary for the driver
to keep its own copy of the sound data. It could be even further simplified (I don't really see any reason for having two different sound queues), but I seem to have reached a point of stability here and I don't want to jinx it by making further changes yet. svn-id: r13705
This commit is contained in:
parent
e830d35a21
commit
bc77ba431a
3
NEWS
3
NEWS
@ -23,7 +23,8 @@ For a more comprehensive changelog for the latest experimental CVS code, see:
|
||||
- ??? [TODO: Somebody of the Sword1 team please fill this in]
|
||||
|
||||
Sword2:
|
||||
- Simplified the memory/resource management.
|
||||
- Simplified the memory/resource management...
|
||||
- ...which led to simplified sound effects handling
|
||||
- Various minor bugfixes.
|
||||
|
||||
BASS
|
||||
|
@ -326,8 +326,8 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], byte *mus
|
||||
// the animated cut-scenes, so this seems like a good place to close
|
||||
// both of them.
|
||||
|
||||
_vm->_sound->closeFx(-1);
|
||||
_vm->_sound->closeFx(-2);
|
||||
_vm->_sound->stopFx(-1);
|
||||
_vm->_sound->stopFx(-2);
|
||||
|
||||
return RD_OK;
|
||||
#else
|
||||
@ -478,8 +478,8 @@ int32 MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], byte
|
||||
// the animated cut-scenes, so this seems like a good place to close
|
||||
// both of them.
|
||||
|
||||
_vm->_sound->closeFx(-1);
|
||||
_vm->_sound->closeFx(-2);
|
||||
_vm->_sound->stopFx(-1);
|
||||
_vm->_sound->stopFx(-2);
|
||||
|
||||
return RD_OK;
|
||||
}
|
||||
|
@ -1028,70 +1028,6 @@ bool Sound::isFxPlaying(int32 id) {
|
||||
return _fx[i]._handle.isActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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::openFx(int32 id, byte *data) {
|
||||
if (!_soundOn)
|
||||
return RD_OK;
|
||||
|
||||
if (id == 0)
|
||||
return RDERR_INVALIDID;
|
||||
|
||||
if (getFxIndex(id) != MAXFX)
|
||||
return RDERR_FXALREADYOPEN;
|
||||
|
||||
// Find a free slot
|
||||
int32 fxi = getFxIndex(0);
|
||||
|
||||
if (fxi == MAXFX) {
|
||||
warning("openFx: Running out of sound slots");
|
||||
|
||||
// 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.
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
_fx[fxi]._id = id;
|
||||
_fx[fxi]._flags = SoundMixer::FLAG_16BITS | SoundMixer::FLAG_LITTLE_ENDIAN;
|
||||
|
||||
WavInfo wavInfo;
|
||||
|
||||
if (!getWavInfo(data, &wavInfo)) {
|
||||
warning("openFx: Not a valida WAV file");
|
||||
return RDERR_INVALIDWAV;
|
||||
}
|
||||
|
||||
if (wavInfo.channels == 2)
|
||||
_fx[fxi]._flags |= SoundMixer::FLAG_STEREO;
|
||||
|
||||
_fx[fxi]._rate = wavInfo.rate;
|
||||
_fx[fxi]._bufSize = wavInfo.samples;
|
||||
|
||||
// Fill the speech buffer with data
|
||||
free(_fx[fxi]._buf);
|
||||
_fx[fxi]._buf = (uint16 *) malloc(_fx[fxi]._bufSize);
|
||||
memcpy(_fx[fxi]._buf, wavInfo.data, _fx[fxi]._bufSize);
|
||||
|
||||
return RD_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function closes a sound effect which has been previously opened for
|
||||
* playing. Sound effects must be closed when they are finished with, otherwise
|
||||
@ -1099,7 +1035,7 @@ int32 Sound::openFx(int32 id, byte *data) {
|
||||
* @param id the id of the sound to close
|
||||
*/
|
||||
|
||||
int32 Sound::closeFx(int32 id) {
|
||||
int32 Sound::stopFx(int32 id) {
|
||||
int i;
|
||||
|
||||
if (!_soundOn)
|
||||
@ -1133,43 +1069,69 @@ int32 Sound::playFx(int32 id, byte *data, uint8 vol, int8 pan, uint8 type) {
|
||||
return RD_OK;
|
||||
|
||||
byte volume = _fxMuted ? 0 : vol * _fxVol;
|
||||
int8 p = _panTable[pan + 16];
|
||||
int32 i, hr;
|
||||
|
||||
if (data) {
|
||||
// All lead-ins and lead-outs I've heard are music, so we use
|
||||
// the music volume setting for them.
|
||||
// All lead-ins and lead-outs I've heard are music, so we use
|
||||
// the music volume setting for them.
|
||||
|
||||
if (type == RDSE_FXLEADIN || type == RDSE_FXLEADOUT) {
|
||||
id = (type == RDSE_FXLEADIN) ? -2 : -1;
|
||||
volume = _musicMuted ? 0 : _musicVolTable[_musicVol];
|
||||
}
|
||||
|
||||
hr = openFx(id, data);
|
||||
if (hr != RD_OK)
|
||||
return hr;
|
||||
if (type == RDSE_FXLEADIN || type == RDSE_FXLEADOUT) {
|
||||
id = (type == RDSE_FXLEADIN) ? -2 : -1;
|
||||
volume = _musicMuted ? 0 : _musicVolTable[_musicVol];
|
||||
}
|
||||
|
||||
i = getFxIndex(id);
|
||||
WavInfo wavInfo;
|
||||
|
||||
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;
|
||||
}
|
||||
if (!getWavInfo(data, &wavInfo)) {
|
||||
warning("playFx: Not a valid WAV file");
|
||||
return RDERR_INVALIDWAV;
|
||||
}
|
||||
|
||||
int32 fxi = getFxIndex(id);
|
||||
|
||||
if (fxi == MAXFX) {
|
||||
// Find a free slot
|
||||
fxi = getFxIndex(0);
|
||||
|
||||
if (fxi == MAXFX) {
|
||||
warning("openFx: Running out of sound slots");
|
||||
|
||||
// There aren't any free sound handles available. This
|
||||
// usually shouldn't happen, but if it does we expire
|
||||
// the first sound effect that isn't currently playing.
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
_fx[fxi]._id = id;
|
||||
}
|
||||
|
||||
if (_fx[fxi]._handle.isActive())
|
||||
return RDERR_FXALREADYOPEN;
|
||||
|
||||
uint32 flags = SoundMixer::FLAG_16BITS | SoundMixer::FLAG_LITTLE_ENDIAN;
|
||||
|
||||
if (wavInfo.channels == 2)
|
||||
flags |= SoundMixer::FLAG_STEREO;
|
||||
|
||||
|
||||
if (type == RDSE_FXLOOP)
|
||||
_fx[i]._flags |= SoundMixer::FLAG_LOOP;
|
||||
flags |= SoundMixer::FLAG_LOOP;
|
||||
else
|
||||
_fx[i]._flags &= ~SoundMixer::FLAG_LOOP;
|
||||
flags &= ~SoundMixer::FLAG_LOOP;
|
||||
|
||||
_fx[i]._volume = vol;
|
||||
_fx[fxi]._volume = vol;
|
||||
|
||||
_vm->_mixer->playRaw(&_fx[i]._handle, _fx[i]._buf, _fx[i]._bufSize, _fx[i]._rate, _fx[i]._flags, -1, volume, p);
|
||||
int8 p = _panTable[pan + 16];
|
||||
|
||||
_vm->_mixer->playRaw(&_fx[fxi]._handle, wavInfo.data, wavInfo.samples, wavInfo.rate, flags, -1, volume, p);
|
||||
|
||||
return RD_OK;
|
||||
}
|
||||
@ -1177,12 +1139,8 @@ int32 Sound::playFx(int32 id, byte *data, uint8 vol, int8 pan, uint8 type) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,10 +44,6 @@ struct FxHandle {
|
||||
int32 _id;
|
||||
bool _paused;
|
||||
int8 _volume;
|
||||
uint16 _rate;
|
||||
uint32 _flags;
|
||||
uint16 *_buf;
|
||||
int32 _bufSize;
|
||||
PlayingSoundHandle _handle;
|
||||
};
|
||||
|
||||
@ -157,9 +153,8 @@ public:
|
||||
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);
|
||||
int32 stopFx(int32 id);
|
||||
void clearAllFx(void);
|
||||
};
|
||||
|
||||
|
@ -40,8 +40,9 @@ namespace Sword2 {
|
||||
// is located in and the number within the cluster
|
||||
|
||||
// If 0, resouces are expelled immediately when they are closed. At the moment
|
||||
// this causes the game to crash, which seems like a bug to me. In fact, it
|
||||
// could be a clue to the mysterious and infrequent crashes...
|
||||
// this causes the sound queue to run out of slots. My only theory is that it's
|
||||
// a script that gets reloaded over and over. That'd clear its local variables
|
||||
// which I guess may cause it to set up the sounds over and over.
|
||||
|
||||
#define CACHE_CLUSTERS 1
|
||||
|
||||
@ -768,6 +769,12 @@ void ResourceManager::removeAll(void) {
|
||||
void ResourceManager::killAll(bool wantInfo) {
|
||||
int nuked = 0;
|
||||
|
||||
// We need to clear the FX queue, because otherwise the sound system
|
||||
// will still believe that the sound resources are in memory, and that
|
||||
// it's ok to close them.
|
||||
|
||||
_vm->clearFxQueue();
|
||||
|
||||
for (uint i = 0; i < _totalResFiles; i++) {
|
||||
// Don't nuke the global variables or the player object!
|
||||
if (i == 1 || i == CUR_PLAYER_ID)
|
||||
|
251
sword2/sound.cpp
251
sword2/sound.cpp
@ -38,94 +38,100 @@
|
||||
|
||||
namespace Sword2 {
|
||||
|
||||
struct FxQueueEntry {
|
||||
uint32 resource; // resource id of sample
|
||||
byte *data; // pointer to WAV data
|
||||
uint16 delay; // cycles to wait before playing (or 'random chance' if FX_RANDOM)
|
||||
uint8 volume; // 0..16
|
||||
int8 pan; // -16..16
|
||||
uint8 type; // FX_SPOT, FX_RANDOM or FX_LOOP
|
||||
};
|
||||
|
||||
// FIXME: Should be in one of the classes, I guess...
|
||||
|
||||
static FxQueueEntry fxQueue[FXQ_LENGTH];
|
||||
|
||||
/**
|
||||
* Initialise the fxq by clearing all the entries.
|
||||
* Initialise the FX queue by clearing all the entries. This is only used at
|
||||
* the start of the game. Later when we need to clear the queue we must also
|
||||
* stop the sound and close the resource.
|
||||
*/
|
||||
|
||||
void Sword2Engine::initFxQueue(void) {
|
||||
for (int i = 0; i < FXQ_LENGTH; i++)
|
||||
_fxQueue[i].resource = 0;
|
||||
fxQueue[i].resource = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the fx queue once every game cycle
|
||||
* Stop all sounds, close their resources and clear the FX queue.
|
||||
*/
|
||||
|
||||
void Sword2Engine::clearFxQueue(void) {
|
||||
for (int i = 0; i < FXQ_LENGTH; i++) {
|
||||
if (fxQueue[i].resource) {
|
||||
_sound->stopFx(i + 1);
|
||||
_resman->closeResource(fxQueue[i].resource);
|
||||
fxQueue[i].resource = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the FX queue once every game cycle
|
||||
*/
|
||||
|
||||
void Sword2Engine::processFxQueue(void) {
|
||||
for (int i = 0; i < FXQ_LENGTH; i++) {
|
||||
if (!_fxQueue[i].resource)
|
||||
if (!fxQueue[i].resource)
|
||||
continue;
|
||||
|
||||
switch (_fxQueue[i].type) {
|
||||
switch (fxQueue[i].type) {
|
||||
case FX_RANDOM:
|
||||
// 1 in 'delay' chance of this fx occurring
|
||||
if (_rnd.getRandomNumber(_fxQueue[i].delay) == 0)
|
||||
if (_rnd.getRandomNumber(fxQueue[i].delay) == 0)
|
||||
triggerFx(i);
|
||||
break;
|
||||
case FX_SPOT:
|
||||
if (_fxQueue[i].delay)
|
||||
_fxQueue[i].delay--;
|
||||
if (fxQueue[i].delay)
|
||||
fxQueue[i].delay--;
|
||||
else {
|
||||
triggerFx(i);
|
||||
_fxQueue[i].type = FX_SPOT2;
|
||||
fxQueue[i].type = FX_SPOT2;
|
||||
}
|
||||
break;
|
||||
case FX_LOOP:
|
||||
triggerFx(i);
|
||||
fxQueue[i].type = FX_LOOPING;
|
||||
break;
|
||||
case FX_SPOT2:
|
||||
// Once the Fx has finished remove it from the queue.
|
||||
// Once the FX has finished remove it from the queue.
|
||||
if (!_sound->isFxPlaying(i + 1)) {
|
||||
_fxQueue[i].resource = 0;
|
||||
_sound->closeFx(i + 1);
|
||||
_sound->stopFx(i + 1);
|
||||
_resman->closeResource(fxQueue[i].resource);
|
||||
fxQueue[i].resource = 0;
|
||||
}
|
||||
break;
|
||||
case FX_LOOPING:
|
||||
// Once the looped FX has started we can ignore it,
|
||||
// but we can't close it since the WAV data is in use.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sword2Engine::triggerFx(uint8 j) {
|
||||
byte *data;
|
||||
int32 id;
|
||||
uint32 rv;
|
||||
void Sword2Engine::triggerFx(uint8 i) {
|
||||
int type;
|
||||
|
||||
id = (uint32) j + 1; // because 0 is not a valid id
|
||||
|
||||
if (_fxQueue[j].type == FX_SPOT) {
|
||||
// load in the sample
|
||||
data = _resman->openResource(_fxQueue[j].resource);
|
||||
data += sizeof(StandardHeader);
|
||||
// wav data gets copied to sound memory
|
||||
rv = _sound->playFx(id, data, _fxQueue[j].volume, _fxQueue[j].pan, RDSE_FXSPOT);
|
||||
// release the sample
|
||||
_resman->closeResource(_fxQueue[j].resource);
|
||||
} else {
|
||||
// random & looped fx are already loaded into sound memory
|
||||
// by fnPlayFx()
|
||||
// - to be referenced by 'j', so pass NULL data
|
||||
|
||||
if (_fxQueue[j].type == FX_RANDOM) {
|
||||
// Not looped
|
||||
rv = _sound->playFx(id, NULL, _fxQueue[j].volume, _fxQueue[j].pan, RDSE_FXSPOT);
|
||||
} else {
|
||||
// Looped
|
||||
rv = _sound->playFx(id, NULL, _fxQueue[j].volume, _fxQueue[j].pan, RDSE_FXLOOP);
|
||||
}
|
||||
}
|
||||
if (fxQueue[i].type == FX_LOOP)
|
||||
type = RDSE_FXLOOP;
|
||||
else
|
||||
type = RDSE_FXSPOT;
|
||||
|
||||
uint32 rv = _sound->playFx(i + 1, fxQueue[i].data, fxQueue[i].volume, fxQueue[i].pan, type);
|
||||
if (rv)
|
||||
debug(5, "SFX ERROR: playFx() returned %.8x", rv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop all looped & random fx and clear the entire queue
|
||||
*/
|
||||
|
||||
void Sword2Engine::clearFxQueue(void) {
|
||||
// stop all fx & remove the samples from sound memory
|
||||
_sound->clearAllFx();
|
||||
|
||||
// clean out the queue
|
||||
initFxQueue();
|
||||
}
|
||||
|
||||
void Sword2Engine::killMusic(void) {
|
||||
_loopingMusicId = 0; // clear the 'looping' flag
|
||||
_sound->stopMusic();
|
||||
@ -159,15 +165,6 @@ int32 Logic::fnPlayFx(int32 *params) {
|
||||
// .
|
||||
// fnStopFx (fx_water);
|
||||
|
||||
uint8 j = 0;
|
||||
byte *data;
|
||||
uint32 id;
|
||||
uint32 rv;
|
||||
|
||||
#ifdef _SWORD2_DEBUG
|
||||
StandardHeader *header;
|
||||
#endif
|
||||
|
||||
if (_vm->_wantSfxDebug) {
|
||||
char type[10];
|
||||
|
||||
@ -191,76 +188,46 @@ int32 Logic::fnPlayFx(int32 *params) {
|
||||
debug(0, "SFX (sample=\"%s\", vol=%d, pan=%d, delay=%d, type=%s)", _vm->fetchObjectName(params[0], buf), params[3], params[4], params[2], type);
|
||||
}
|
||||
|
||||
while (j < FXQ_LENGTH && _vm->_fxQueue[j].resource != 0)
|
||||
j++;
|
||||
int i;
|
||||
|
||||
if (j == FXQ_LENGTH)
|
||||
// Find a free slot in the FX queue
|
||||
|
||||
for (i = 0; i < FXQ_LENGTH; i++) {
|
||||
if (!fxQueue[i].resource)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == FXQ_LENGTH) {
|
||||
warning("No free slot in FX queue");
|
||||
return IR_CONT;
|
||||
|
||||
_vm->_fxQueue[j].resource = params[0]; // wav resource id
|
||||
_vm->_fxQueue[j].type = params[1]; // FX_SPOT, FX_LOOP or FX_RANDOM
|
||||
|
||||
if (_vm->_fxQueue[j].type == FX_RANDOM) {
|
||||
// 'delay' param is the intended average no. seconds between
|
||||
// playing this effect
|
||||
_vm->_fxQueue[j].delay = params[2] * 12;
|
||||
} else {
|
||||
// FX_SPOT or FX_LOOP:
|
||||
// 'delay' is no. frames to wait before playing
|
||||
_vm->_fxQueue[j].delay = params[2];
|
||||
}
|
||||
|
||||
_vm->_fxQueue[j].volume = params[3]; // 0..16
|
||||
_vm->_fxQueue[j].pan = params[4]; // -16..16
|
||||
fxQueue[i].resource = params[0];
|
||||
fxQueue[i].type = params[1];
|
||||
fxQueue[i].delay = params[2];
|
||||
|
||||
if (_vm->_fxQueue[j].type == FX_SPOT) {
|
||||
// "pre-load" the sample; this gets it into memory
|
||||
data = _vm->_resman->openResource(_vm->_fxQueue[j].resource);
|
||||
|
||||
#ifdef _SWORD2_DEBUG
|
||||
header = (StandardHeader *) data;
|
||||
if (header->fileType != WAV_FILE)
|
||||
error("fnPlayFx given invalid resource");
|
||||
#endif
|
||||
|
||||
// but then releases it to "age" out if the space is needed
|
||||
_vm->_resman->closeResource(_vm->_fxQueue[j].resource);
|
||||
} else {
|
||||
// random & looped fx
|
||||
|
||||
id = (uint32) j + 1; // because 0 is not a valid id
|
||||
|
||||
// load in the sample
|
||||
data = _vm->_resman->openResource(_vm->_fxQueue[j].resource);
|
||||
|
||||
#ifdef _SWORD2_DEBUG
|
||||
header = (StandardHeader *) data;
|
||||
if (header->fileType != WAV_FILE)
|
||||
error("fnPlayFx given invalid resource");
|
||||
#endif
|
||||
|
||||
data += sizeof(StandardHeader);
|
||||
|
||||
// copy it to sound memory, using position in queue as 'id'
|
||||
rv = _vm->_sound->openFx(id, data);
|
||||
|
||||
if (rv)
|
||||
debug(5, "SFX ERROR: openFx() returned %.8x", rv);
|
||||
|
||||
// release the sample
|
||||
_vm->_resman->closeResource(_vm->_fxQueue[j].resource);
|
||||
if (fxQueue[i].type == FX_RANDOM) {
|
||||
// For spot effects and loops the dela is the number of frames
|
||||
// to wait. For random effects, however, it's the average
|
||||
// number of seconds between playing the sound, so we have to
|
||||
// multiply by the frame rate.
|
||||
fxQueue[i].delay *= 12;
|
||||
}
|
||||
|
||||
if (_vm->_fxQueue[j].type == FX_LOOP) {
|
||||
// play now, rather than in processFxQueue where it was
|
||||
// getting played again & again!
|
||||
_vm->triggerFx(j);
|
||||
}
|
||||
fxQueue[i].volume = params[3];
|
||||
fxQueue[i].pan = params[4];
|
||||
|
||||
// in case we want to call fnStopFx() later, to kill this fx
|
||||
// (mainly for FX_LOOP & FX_RANDOM)
|
||||
byte *data = _vm->_resman->openResource(params[0]);
|
||||
StandardHeader *header = (StandardHeader *) data;
|
||||
|
||||
_scriptVars[RESULT] = j;
|
||||
assert(header->fileType == WAV_FILE);
|
||||
|
||||
fxQueue[i].data = data + sizeof(StandardHeader);
|
||||
|
||||
// Keep track of the index in the loop so that fnStopFx() can be used
|
||||
// later to kill this sound. Mainly for FX_LOOP and FX_RANDOM.
|
||||
|
||||
_scriptVars[RESULT] = i;
|
||||
return IR_CONT;
|
||||
}
|
||||
|
||||
@ -270,7 +237,7 @@ int32 Logic::fnSoundFetch(int32 *params) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the volume and pan of a currently playing fx
|
||||
* Alter the volume and pan of a currently playing FX
|
||||
*/
|
||||
|
||||
int32 Logic::fnSetFxVolAndPan(int32 *params) {
|
||||
@ -281,14 +248,12 @@ int32 Logic::fnSetFxVolAndPan(int32 *params) {
|
||||
|
||||
debug(5, "fnSetFxVolAndPan(%d, %d, %d)", params[0], params[1], params[2]);
|
||||
|
||||
// setFxIdVolumePan(int32 id, uint8 vol, uint8 pan);
|
||||
// driver fx_id is 1 + <pos in queue>
|
||||
_vm->_sound->setFxIdVolumePan(1 + params[0], params[1], params[2]);
|
||||
_vm->_sound->setFxIdVolumePan(params[0] + 1, params[1], params[2]);
|
||||
return IR_CONT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the volume of a currently playing fx
|
||||
* Alter the volume of a currently playing FX
|
||||
*/
|
||||
|
||||
int32 Logic::fnSetFxVol(int32 *params) {
|
||||
@ -296,41 +261,33 @@ int32 Logic::fnSetFxVol(int32 *params) {
|
||||
// fnPlayFx
|
||||
// 1 new volume (0..16)
|
||||
|
||||
// SetFxIdVolume(int32 id, uint8 vol);
|
||||
_vm->_sound->setFxIdVolume(1 + params[0], params[1]);
|
||||
_vm->_sound->setFxIdVolume(params[0] + 1, params[1]);
|
||||
return IR_CONT;
|
||||
}
|
||||
|
||||
int32 Logic::fnStopFx(int32 *params) {
|
||||
// params: 0 position in queue
|
||||
|
||||
// This will stop looped & random fx instantly, and remove the fx
|
||||
// from the queue. So although it doesn't stop spot fx, it will
|
||||
// remove them from the queue if they haven't yet played
|
||||
int32 i = params[0];
|
||||
uint32 rv = _vm->_sound->stopFx(i + 1);
|
||||
|
||||
uint8 j = (uint8) params[0];
|
||||
uint32 id;
|
||||
uint32 rv;
|
||||
if (rv)
|
||||
debug(5, "SFX ERROR: closeFx() returned %.8x", rv);
|
||||
|
||||
if (_vm->_fxQueue[j].type == FX_RANDOM || _vm->_fxQueue[j].type == FX_LOOP) {
|
||||
id = (uint32) j + 1; // because 0 is not a valid id
|
||||
|
||||
// stop fx & remove sample from sound memory
|
||||
rv = _vm->_sound->closeFx(id);
|
||||
|
||||
if (rv)
|
||||
debug(5, "SFX ERROR: closeFx() returned %.8x", rv);
|
||||
// Remove from queue
|
||||
if (fxQueue[i].resource) {
|
||||
_vm->_resman->closeResource(fxQueue[i].resource);
|
||||
fxQueue[i].resource = 0;
|
||||
}
|
||||
|
||||
// remove from queue
|
||||
_vm->_fxQueue[j].resource = 0;
|
||||
|
||||
return IR_CONT;
|
||||
}
|
||||
|
||||
int32 Logic::fnStopAllFx(int32 *params) {
|
||||
// Stops all looped & random fx and clears the entire queue
|
||||
/**
|
||||
* Stops all FX and clears the entire FX queue.
|
||||
*/
|
||||
|
||||
int32 Logic::fnStopAllFx(int32 *params) {
|
||||
// params: none
|
||||
|
||||
_vm->clearFxQueue();
|
||||
|
@ -38,10 +38,14 @@ namespace Sword2 {
|
||||
// fx types
|
||||
|
||||
enum {
|
||||
// These three types correspond to types set by the scripts
|
||||
FX_SPOT = 0,
|
||||
FX_LOOP = 1,
|
||||
FX_RANDOM = 2,
|
||||
FX_SPOT2 = 3
|
||||
|
||||
// These are used for FX queue bookkeeping
|
||||
FX_SPOT2 = 3,
|
||||
FX_LOOPING = 4
|
||||
};
|
||||
|
||||
} // End of namespace Sword2
|
||||
|
@ -321,16 +321,6 @@ public:
|
||||
|
||||
void setScrolling(void);
|
||||
|
||||
struct FxQueueEntry {
|
||||
uint32 resource; // resource id of sample
|
||||
uint16 delay; // cycles to wait before playing (or 'random chance' if FX_RANDOM)
|
||||
uint8 volume; // 0..16
|
||||
int8 pan; // -16..16
|
||||
uint8 type; // FX_SPOT, FX_RANDOM or FX_LOOP
|
||||
};
|
||||
|
||||
FxQueueEntry _fxQueue[FXQ_LENGTH];
|
||||
|
||||
// used to store id of tunes that loop, for save & restore
|
||||
uint32 _loopingMusicId;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user