Rewrote the music code. It now follows the same basic idea as the one in

BS2, which has worked pretty well so far. I haven't implemented pausing and
volume since the code I replaced didn't have it either, as far as I could
tell.

svn-id: r12070
This commit is contained in:
Torbjörn Andersson 2004-01-01 15:22:15 +00:00
parent 033a847e77
commit 18f8916c3a
4 changed files with 143 additions and 175 deletions

View File

@ -231,7 +231,6 @@ uint8 SwordControl::runPanel(void) {
_music->startMusic(61, 1);
do {
_music->stream();
if (newMode) {
mode = newMode;
fullRefresh = true;

View File

@ -19,192 +19,149 @@
*
*/
// todo: add fadeout, crossfading.
// this code always loops. make it depend on _loopFlag
#include "stdafx.h"
#include "music.h"
#include "sound/mixer.h"
#include "common/util.h"
#include "common/file.h"
// This means fading takes about half a second. This may need some tuning...
#define FADE_SAMPLES 5512
// These functions are only called from SwordMusic, so I'm just going to
// assume that if locking is needed it has already been taken care of.
void SwordMusicHandle::fadeDown() {
if (_fading < 0)
_fading = -_fading;
else if (_fading == 0)
_fading = FADE_SAMPLES;
}
void SwordMusicHandle::fadeUp() {
if (_fading > 0)
_fading = -_fading;
else if (_fading == 0)
_fading = -FADE_SAMPLES;
}
bool SwordMusicHandle::endOfData() const {
return !streaming();
}
int SwordMusicHandle::readBuffer(int16 *buffer, const int numSamples) {
int samples;
for (samples = 0; samples < numSamples && !endOfData(); samples++)
*buffer++ = read();
return samples;
}
int16 SwordMusicHandle::read() {
if (!streaming())
return 0;
int16 sample = _file.readUint16LE();
if (_file.ioFailed()) {
if (!_looping) {
stop();
return 0;
}
_file.clearIOFailed();
_file.seek(WAVEHEADERSIZE);
sample = _file.readUint16LE();
}
if (_fading > 0) {
if (--_fading == 0) {
_looping = false;
_file.close();
}
sample = (sample * _fading) / FADE_SAMPLES;
} else if (_fading < 0) {
_fading++;
sample = (sample * (FADE_SAMPLES + _fading)) / FADE_SAMPLES;
}
return sample;
}
bool SwordMusicHandle::play(const char *filename, bool loop) {
uint8 wavHeader[WAVEHEADERSIZE];
stop();
_file.open(filename);
if (!_file.isOpen())
return false;
_file.read(wavHeader, WAVEHEADERSIZE);
_stereo = (READ_LE_UINT16(wavHeader + 0x16) == 2);
_rate = READ_LE_UINT16(wavHeader + 0x18);
_looping = loop;
fadeUp();
return true;
}
void SwordMusicHandle::stop() {
if (_file.isOpen())
_file.close();
_fading = 0;
_looping = false;
}
SwordMusic::SwordMusic(OSystem *system, SoundMixer *pMixer) {
_system = system;
_mixer = pMixer;
_mixer->setupPremix(passMixerFunc, this);
_fading = false;
_playing = false;
_loop = false;
_mutex = _system->create_mutex();
_fadeSmpInBuf = _fadeBufPos = _waveSize = _wavePos = _bufPos = _smpInBuf = 0;
assert(_mixer->getOutputRate() == 22050);
_fadeBuf = NULL;
_musicBuf = NULL;
_converter[0] = NULL;
_converter[1] = NULL;
}
SwordMusic::~SwordMusic() {
_mixer->setupPremix(0, 0);
delete _converter[0];
delete _converter[1];
}
void SwordMusic::passMixerFunc(void *param, int16 *buf, uint len) {
((SwordMusic*)param)->mixer(buf, len);
}
void SwordMusic::mixTo(int16 *src, int16 *dst, uint32 len) {
if (!_playing)
memset(dst, 0, len * 8);
if (!_fading) { // no fading, simply copy it over
for (uint32 cnt = 0; cnt < len; cnt++)
dst[(cnt << 2) | 0] = dst[(cnt << 2) | 1] =
dst[(cnt << 2) | 2] = dst[(cnt << 2) | 3] = (int16)READ_LE_UINT16(src + cnt);
} else {
if (_fadeBuf) { // do a cross fade
for (uint32 cnt = 0; cnt < len; cnt++) {
int16 resVal = ((int16)READ_LE_UINT16(_fadeBuf + _fadeBufPos) * _fadeVal) >> 15;
resVal += ((int16)READ_LE_UINT16(src + cnt) * (32768 - _fadeVal)) >> 15;
dst[(cnt << 2) | 0] = dst[(cnt << 2) | 1] =
dst[(cnt << 2) | 2] = dst[(cnt << 2) | 3] = resVal;
_fadeVal--;
_fadeBufPos++;
_fadeSmpInBuf--;
}
if ((!_fadeVal) || (!_fadeSmpInBuf)) {
free(_fadeBuf);
_fadeBuf = NULL;
_fading = false;
}
if (_fadeBufPos == BUFSIZE)
_fadeBufPos = 0;
} else { // simple fadeout
for (uint32 cnt = 0; cnt < len; cnt++) {
dst[(cnt << 2) | 0] = dst[(cnt << 2) | 1] =
dst[(cnt << 2) | 2] = dst[(cnt << 2) | 3] =
((int16)READ_LE_UINT16(src + cnt) * _fadeVal) >> 15;
_fadeVal--;
}
if ((!_fadeVal) || (!_smpInBuf)) {
_fading = _playing = false;
free(_musicBuf);
_musicBuf = NULL;
}
}
}
}
void SwordMusic::mixer(int16 *buf, uint32 len) {
if (!_playing) {
memset(buf, 0, 2 * len * sizeof(int16));
return;
}
uint32 remain = 0;
if (_smpInBuf < (len >> 1)) {
if (_loop)
return;
remain = (len >> 1) - _smpInBuf;
len = _smpInBuf << 1;
}
_system->lock_mutex(_mutex);
len >>= 1;
while (len) {
uint32 length = len;
length = MIN(length, BUFSIZE - _bufPos);
if (_fading && _fadeBuf) {
length = MIN(length, (uint32)_fadeVal);
length = MIN(length, _fadeSmpInBuf);
length = MIN(length, BUFSIZE - _fadeBufPos);
Common::StackLock lock(_mutex);
for (int i = 0; i < ARRAYSIZE(_handles); i++) {
if (_handles[i].streaming() && _converter[i]) {
st_volume_t vol = 255;
_converter[i]->flow(_handles[i], buf, len, vol, vol);
}
mixTo(_musicBuf + _bufPos, buf, length);
len -= length;
buf += 4 * length;
_bufPos += length;
_smpInBuf -= length;
if (_bufPos == BUFSIZE)
_bufPos = 0;
}
if (remain) {
memset(buf, 0, remain * 8);
_playing = false;
}
_system->unlock_mutex(_mutex);
}
void SwordMusic::stream(void) {
// make sure we've got enough samples in buffer.
if ((_smpInBuf < 4 * SAMPLERATE) && _playing && _musicFile.isOpen()) {
_system->lock_mutex(_mutex);
uint32 loadTotal = BUFSIZE - _smpInBuf;
while (uint32 doLoad = loadTotal) {
if (BUFSIZE - ((_bufPos + _smpInBuf) % BUFSIZE) < loadTotal)
doLoad = BUFSIZE - (_bufPos + _smpInBuf) % BUFSIZE;
doLoad = MIN(doLoad, _waveSize - _wavePos);
int16 *dest = _musicBuf + ((_bufPos + _smpInBuf) % BUFSIZE);
_musicFile.read(dest, doLoad * 2);
_wavePos += doLoad;
if (_wavePos == _waveSize) {
if (_loop) {
_wavePos = 0;
_musicFile.seek(WAVEHEADERSIZE);
} else
loadTotal = doLoad;
}
loadTotal -= doLoad;
_smpInBuf += doLoad;
}
_system->unlock_mutex(_mutex);
}
}
void SwordMusic::startMusic(int32 tuneId, int32 loopFlag) {
_system->lock_mutex(_mutex);
_loop = (loopFlag > 0);
if (tuneId) {
if (_musicFile.isOpen())
_musicFile.close();
Common::StackLock lock(_mutex);
if (strlen(_tuneList[tuneId]) > 0) {
int newStream = 0;
if (_handles[0].streaming() && _handles[1].streaming()) {
// If both handles are playing, stop the one that's
// fading down.
if (_handles[0].fading() > 0)
_handles[0].stop();
else
_handles[1].stop();
}
if (_handles[0].streaming()) {
_handles[0].fadeDown();
newStream = 1;
} else if (_handles[1].streaming()) {
_handles[1].fadeDown();
newStream = 0;
}
char fName[20];
sprintf(fName, "music/%s.wav", _tuneList[tuneId]);
_musicFile.open(fName);
if (_musicFile.isOpen()) {
if (_playing) { // do a cross fade
_fadeBuf = _musicBuf;
_fadeBufPos = _bufPos;
_fadeSmpInBuf = _smpInBuf;
_fading = true;
_fadeVal = 32768;
} else
_fading = false;
_musicBuf = (int16*)malloc(BUFSIZE * 2);
_musicFile.seek(0x28);
_waveSize = _musicFile.readUint32LE() / 2;
_wavePos = 0;
_smpInBuf = 0;
_bufPos = 0;
_playing = true;
} else {
_fading = true;
_fadeVal = 32768;
if (_fadeBuf) {
free(_fadeBuf);
_fadeBuf = NULL;
}
}
} else {
if (_playing)
fadeDown();
if (_musicFile.isOpen())
_musicFile.close();
}
_system->unlock_mutex(_mutex);
stream();
}
void SwordMusic::fadeDown(void) {
_fadeVal = 32768;
_fading = true;
if (_fadeBuf) {
free(_fadeBuf);
_fadeBuf = NULL;
_handles[newStream].play(fName, loopFlag);
delete _converter[newStream];
_converter[newStream] = makeRateConverter(_handles[newStream].getRate(), _mixer->getOutputRate(), _handles[newStream].isStereo(), false);
}
}
void SwordMusic::fadeDown() {
Common::StackLock lock(_mutex);
for (int i = 0; i < ARRAYSIZE(_handles); i++)
if (_handles[i].streaming())
_handles[i].fadeDown();
}

View File

@ -25,39 +25,53 @@
#include "scummsys.h"
#include "common/system.h"
#include "common/file.h"
#include "sound/audiostream.h"
#include "sound/rate.h"
#define TOTAL_TUNES 270
#define SAMPLERATE 11025
#define BUFSIZE (6 * SAMPLERATE)
#define WAVEHEADERSIZE 0x2C
class SoundMixer;
class SwordMusicHandle : public AudioInputStream {
private:
File _file;
bool _looping;
int32 _fading;
int _rate;
bool _stereo;
public:
SwordMusicHandle() : _looping(false), _fading(0) {}
virtual int readBuffer(int16 *buffer, const int numSamples);
int16 read();
bool play(const char *filename, bool loop);
void stop();
void fadeUp();
void fadeDown();
bool streaming() const { return _file.isOpen(); }
int32 fading() { return _fading; }
bool endOfData() const;
bool endOfStream() const { return false; }
bool isStereo() const { return _stereo; }
int getRate() const { return _rate; }
};
class SwordMusic {
public:
SwordMusic(OSystem *system, SoundMixer *pMixer);
~SwordMusic();
void stream(void);
void startMusic(int32 tuneId, int32 loopFlag);
void fadeDown(void);
void fadeDown();
private:
File _musicFile;
SwordMusicHandle _handles[2];
RateConverter *_converter[2];
OSystem *_system;
SoundMixer *_mixer;
bool _fading;
uint16 _fadeVal;
bool _playing;
bool _loop;
OSystem::MutexRef _mutex;
static void passMixerFunc(void *param, int16 *buf, uint len);
void mixTo(int16 *src, int16 *dst, uint32 len);
void mixer(int16 *buf, uint32 len);
static const char _tuneList[TOTAL_TUNES][8]; // in staticres.cpp
uint32 _waveSize, _wavePos;
int16 *_musicBuf; // samples for 6 seconds
uint32 _bufPos, _smpInBuf;
int16 *_fadeBuf;
uint32 _fadeBufPos, _fadeSmpInBuf;
};
#endif // BSMUSIC_H

View File

@ -1116,7 +1116,6 @@ uint8 SwordEngine::mainLoop(void) {
SwordLogic::_scriptVars[SCREEN] = SwordLogic::_scriptVars[NEW_SCREEN];
do {
_music->stream();
uint32 frameTime = _system->get_msecs();
_logic->engine();
_logic->updateScreenParams(); // sets scrolling
@ -1154,7 +1153,6 @@ uint8 SwordEngine::mainLoop(void) {
if ((retCode == 0) && (SwordLogic::_scriptVars[SCREEN] != 53) && _systemVars.wantFade) {
_screen->fadeDownPalette();
while (_screen->stillFading()) {
_music->stream();
_screen->updateScreen();
delay(1000/12);
}