mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-12 03:56:20 +00:00
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:
parent
033a847e77
commit
18f8916c3a
@ -231,7 +231,6 @@ uint8 SwordControl::runPanel(void) {
|
||||
_music->startMusic(61, 1);
|
||||
|
||||
do {
|
||||
_music->stream();
|
||||
if (newMode) {
|
||||
mode = newMode;
|
||||
fullRefresh = true;
|
||||
|
271
sword1/music.cpp
271
sword1/music.cpp
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user