diff options
Diffstat (limited to 'sword1/music.cpp')
-rw-r--r-- | sword1/music.cpp | 145 |
1 files changed, 110 insertions, 35 deletions
diff --git a/sword1/music.cpp b/sword1/music.cpp index 98a1b69000..9ec8358ecc 100644 --- a/sword1/music.cpp +++ b/sword1/music.cpp @@ -32,12 +32,14 @@ SwordMusic::SwordMusic(OSystem *system, SoundMixer *pMixer) { _system = system; _mixer = pMixer; _mixer->setupPremix(passMixerFunc, this); - _fading = 0; + _fading = false; _playing = false; _loop = false; _mutex = _system->create_mutex(); - _waveSize = _wavePos = _bufPos = _smpInBuf = 0; + _fadeSmpInBuf = _fadeBufPos = _waveSize = _wavePos = _bufPos = _smpInBuf = 0; assert(_mixer->getOutputRate() == 22050); + _fadeBuf = NULL; + _musicBuf = NULL; } SwordMusic::~SwordMusic() { @@ -48,51 +50,103 @@ void SwordMusic::passMixerFunc(void *param, int16 *buf, uint len) { ((SwordMusic*)param)->mixer(buf, len); } -void SwordMusic::mixer(int16 *buf, uint len) { +void SwordMusic::mixTo(int16 *src, int16 *dst, uint32 len) { if (!_playing) - memset(buf, 0, 2 * len * sizeof(int16)); - else { - _system->lock_mutex(_mutex); - len >>= 1; - if (len <= _smpInBuf) { - uint32 maxLen = BUFSIZE - _bufPos; - if (len >= maxLen) { - for (uint32 cnt = 0; cnt < maxLen; cnt++) - buf[(cnt << 2) | 0] = buf[(cnt << 2) | 1] = - buf[(cnt << 2) | 2] = buf[(cnt << 2) | 3] = (int16)READ_LE_UINT16(_musicBuf + _bufPos + cnt); - _smpInBuf -= maxLen; - _bufPos = 0; - len -= maxLen; - buf += maxLen * 4; + 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 (len) { - for (uint32 cnt = 0; cnt < len; cnt++) - buf[(cnt << 2) | 0] = buf[(cnt << 2) | 1] = - buf[(cnt << 2) | 2] = buf[(cnt << 2) | 3] = (int16)READ_LE_UINT16(_musicBuf + _bufPos + cnt); - _smpInBuf -= len; - _bufPos += len; + 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) { + _fading = _playing = false; + free(_musicBuf); + _musicBuf = NULL; } } - _system->unlock_mutex(_mutex); } } +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) { + length = MIN(length, (uint32)_fadeVal); + length = MIN(length, _fadeSmpInBuf); + length = MIN(length, BUFSIZE - _fadeBufPos); + } + 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 < SAMPLERATE) && _playing) { + if ((_smpInBuf < 4 * SAMPLERATE) && _playing) { _system->lock_mutex(_mutex); uint32 loadTotal = BUFSIZE - _smpInBuf; while (uint32 doLoad = loadTotal) { if (BUFSIZE - ((_bufPos + _smpInBuf) % BUFSIZE) < loadTotal) doLoad = BUFSIZE - (_bufPos + _smpInBuf) % BUFSIZE; - if (_waveSize - _wavePos < doLoad) - doLoad = _waveSize - _wavePos; + doLoad = MIN(doLoad, _waveSize - _wavePos); + int16 *dest = _musicBuf + ((_bufPos + _smpInBuf) % BUFSIZE); _musicFile.read(dest, doLoad * 2); _wavePos += doLoad; if (_wavePos == _waveSize) { - _wavePos = 0; - _musicFile.seek(WAVEHEADERSIZE); + if (_loop) { + _wavePos = 0; + _musicFile.seek(WAVEHEADERSIZE); + } else + loadTotal = doLoad; } loadTotal -= doLoad; _smpInBuf += doLoad; @@ -104,28 +158,49 @@ void SwordMusic::stream(void) { void SwordMusic::startMusic(int32 tuneId, int32 loopFlag) { _system->lock_mutex(_mutex); _loop = (loopFlag > 0); - if (tuneId) { + if (tuneId) { if (_musicFile.isOpen()) _musicFile.close(); 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 - _playing = false; - } else - _playing = false; + } else { + _fading = true; + _fadeVal = 32768; + if (_fadeBuf) { + free(_fadeBuf); + _fadeBuf = NULL; + } + } + } else if (_playing) + fadeDown(); _system->unlock_mutex(_mutex); stream(); } void SwordMusic::fadeDown(void) { - warning("stub: SwordMusic::fadeDown"); + _fadeVal = 32768; + _fading = true; + if (_fadeBuf) { + free(_fadeBuf); + _fadeBuf = NULL; + } } |