diff options
-rw-r--r-- | engines/scumm/player_v2cms.cpp | 273 | ||||
-rw-r--r-- | engines/scumm/player_v2cms.h | 26 | ||||
-rw-r--r-- | engines/scumm/scumm.cpp | 8 | ||||
-rw-r--r-- | engines/scumm/sound.cpp | 27 |
4 files changed, 176 insertions, 158 deletions
diff --git a/engines/scumm/player_v2cms.cpp b/engines/scumm/player_v2cms.cpp index 21e7f193b5..c39b360197 100644 --- a/engines/scumm/player_v2cms.cpp +++ b/engines/scumm/player_v2cms.cpp @@ -70,40 +70,40 @@ static const byte freqTable[] = { 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0 };*/ -static const byte octaveTable[] = { - 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, - 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, - 0x00, 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, - 0x01, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, - 0x01, 0x08, 0x01, 0x09, 0x01, 0x0A, 0x01, 0x0B, - 0x02, 0x00, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, - 0x02, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x07, - 0x02, 0x08, 0x02, 0x09, 0x02, 0x0A, 0x02, 0x0B, - 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, - 0x03, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, - 0x03, 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, - 0x04, 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, - 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, - 0x04, 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, - 0x05, 0x00, 0x05, 0x01, 0x05, 0x02, 0x05, 0x03, - 0x05, 0x04, 0x05, 0x05, 0x05, 0x06, 0x05, 0x07, - 0x05, 0x08, 0x05, 0x09, 0x05, 0x0A, 0x05, 0x0B, - 0x06, 0x00, 0x06, 0x01, 0x06, 0x02, 0x06, 0x03, - 0x06, 0x04, 0x06, 0x05, 0x06, 0x06, 0x06, 0x07, - 0x06, 0x08, 0x06, 0x09, 0x06, 0x0A, 0x06, 0x0B, - 0x07, 0x00, 0x07, 0x01, 0x07, 0x02, 0x07, 0x03, - 0x07, 0x04, 0x07, 0x05, 0x07, 0x06, 0x07, 0x07, - 0x07, 0x08, 0x07, 0x09, 0x07, 0x0A, 0x07, 0x0B, - 0x08, 0x00, 0x08, 0x01, 0x08, 0x02, 0x08, 0x03, - 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x08, 0x07, - 0x08, 0x08, 0x08, 0x09, 0x08, 0x0A, 0x08, 0x0B, - 0x09, 0x00, 0x09, 0x01, 0x09, 0x02, 0x09, 0x03, - 0x09, 0x04, 0x09, 0x05, 0x09, 0x06, 0x09, 0x07, - 0x09, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x09, 0x0B, - 0x0A, 0x00, 0x0A, 0x01, 0x0A, 0x02, 0x0A, 0x03, - 0x0A, 0x04, 0x0A, 0x05, 0x0A, 0x06, 0x0A, 0x07, - 0x0A, 0x08, 0x0A, 0x09, 0x0A, 0x0A, 0x0A, 0x0B +static const uint16 noteTable[] = { + 0x000, 0x100, 0x200, 0x300, + 0x400, 0x500, 0x600, 0x700, + 0x800, 0x900, 0xA00, 0xB00, + 0x001, 0x101, 0x201, 0x301, + 0x401, 0x501, 0x601, 0x701, + 0x801, 0x901, 0xA01, 0xB01, + 0x002, 0x102, 0x202, 0x302, + 0x402, 0x502, 0x602, 0x702, + 0x802, 0x902, 0xA02, 0xB02, + 0x003, 0x103, 0x203, 0x303, + 0x403, 0x503, 0x603, 0x703, + 0x803, 0x903, 0xA03, 0xB03, + 0x004, 0x104, 0x204, 0x304, + 0x404, 0x504, 0x604, 0x704, + 0x804, 0x904, 0xA04, 0xB04, + 0x005, 0x105, 0x205, 0x305, + 0x405, 0x505, 0x605, 0x705, + 0x805, 0x905, 0xA05, 0xB05, + 0x006, 0x106, 0x206, 0x306, + 0x406, 0x506, 0x606, 0x706, + 0x806, 0x906, 0xA06, 0xB06, + 0x007, 0x107, 0x207, 0x307, + 0x407, 0x507, 0x607, 0x707, + 0x807, 0x907, 0xA07, 0xB07, + 0x008, 0x108, 0x208, 0x308, + 0x408, 0x508, 0x608, 0x708, + 0x808, 0x908, 0xA08, 0xB08, + 0x009, 0x109, 0x209, 0x309, + 0x409, 0x509, 0x609, 0x709, + 0x809, 0x909, 0xA09, 0xB09, + 0x00A, 0x10A, 0x20A, 0x30A, + 0x40A, 0x50A, 0x60A, 0x70A, + 0x80A, 0x90A, 0xA0A, 0xB0A }; static const byte attackRate[] = { @@ -131,6 +131,12 @@ static const byte volumeTable[] = { 0x33, 0x44, 0x55, 0x66, 0x88, 0xAA, 0xCC, 0xFF }; +static const byte cmsInitData[13*2] = { + 0x1C, 0x02, + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, + 0x14, 0x3F, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1C, 0x01 +}; + Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer) : Player_V2Base(scumm, mixer, true) { int i; @@ -142,6 +148,7 @@ Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer) memset(_cmsChips, 0, sizeof(MusicChip)*2); _midiDelay = _octaveMask = _looping = _tempo = 0; _midiData = _midiSongBegin = 0; + _musicTimer = _musicTimerTicks = 0; _loadedMidiSong = 0; memset(_midiChannel, 0, sizeof(Voice2*)*16); memset(_midiChannelUse, 0, sizeof(byte)*16); @@ -173,12 +180,6 @@ Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer) // inits the CMS Emulator like in the original _cmsEmu = new CMSEmulator(_sampleRate); - static const byte cmsInitData[13*2] = { - 0x1C, 0x02, - 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, - 0x14, 0x3F, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1C, 0x01 - }; - i = 0; for (int cmsPort = 0x220; i < 2; cmsPort += 2, ++i) { for (int off = 0; off < 13; ++off) { @@ -200,6 +201,10 @@ Player_V2CMS::~Player_V2CMS() { void Player_V2CMS::setMusicVolume(int vol) { } +int Player_V2CMS::getMusicTimer() { + return _midiData ? _musicTimer : Player_V2Base::getMusicTimer(); +} + void Player_V2CMS::stopAllSounds() { Common::StackLock lock(_mutex); @@ -211,6 +216,7 @@ void Player_V2CMS::stopAllSounds() { _midiData = 0; _midiSongBegin = 0; _midiDelay = 0; + _musicTimer = _musicTimerTicks = 0; offAllChannels(); } @@ -244,6 +250,7 @@ void Player_V2CMS::startSound(int nr) { assert(data); if (data[6] == 0x80) { + _musicTimer = _musicTimerTicks = 0; loadMidiData(data, nr); } else { int cprio = _current_data ? *(_current_data + _header_len) : 0; @@ -351,11 +358,17 @@ int Player_V2CMS::getSoundStatus(int nr) const { return _current_nr == nr || _next_nr == nr || _loadedMidiSong == nr; } -void Player_V2CMS::processMidiData(uint ticks) { +void Player_V2CMS::processMidiData() { byte *currentData = _midiData; byte command = 0x00; int16 temp = 0; + ++_musicTimerTicks; + if (_musicTimerTicks > 60) { + _musicTimerTicks = 0; + ++_musicTimer; + } + if (!_midiDelay) { while (true) { if ((command = *currentData++) == 0xFF) { @@ -365,6 +378,8 @@ void Player_V2CMS::processMidiData(uint ticks) { continue; } _midiData = _midiSongBegin = 0; + _midiDelay = 0; + _loadedMidiSong = 0; offAllChannels(); return; } else { @@ -400,7 +415,7 @@ void Player_V2CMS::processMidiData(uint ticks) { _midiDelay = temp; } - _midiDelay -= ticks; + --_midiDelay; if (_midiDelay < 0) _midiDelay = 0; @@ -415,27 +430,21 @@ int Player_V2CMS::readBuffer(int16 *buffer, const int numSamples) { // maybe this needs a complete rewrite do { - if (_midiData) { - --_clkFrequenz; - if (!(_clkFrequenz & 0x01)) { - playVoice(); - } - - _tempoSum += _tempo; - // FIXME: _tempoSum is declared as char; on some systems char is unsigned. - // E.g. on OS X. Hence the following check is always false. - // Moral of the story: Use uint8, int8 or any of the other types provided by - // ScummVM if you want to ensure signedness and number of available bits. - if (_tempoSum < 0) { - // this have to be called in the same rate as in the original (I think) - processMidiData(1); + if (!(_next_tick >> FIXP_SHIFT)) { + if (_midiData) { + --_clkFrequenz; + if (!(_clkFrequenz & 0x01)) + playVoice(); + + int newTempoSum = _tempo + _tempoSum; + _tempoSum = newTempoSum & 0xFF; + if (newTempoSum > 0xFF) + processMidiData(); + } else { + nextTick(); + play(); } - } - - if (!(_next_tick >> FIXP_SHIFT) && !_midiData) { _next_tick += _tick_len; - nextTick(); - play(); } step = len; @@ -456,29 +465,26 @@ void Player_V2CMS::playVoice() { } _octaveMask = 0xF0; - Voice2 *voice =0; + Voice2 *voice = 0; for (int i = 0; i < 8; ++i) { voice = &_cmsVoices[i]; _octaveMask = ~_octaveMask; if (voice->chanNumber != 0xFF) { processChannel(voice); - continue; - } - - if (!voice->curVolume) { - *(voice->amplitudeOutput) = 0; - } + } else { + if (!voice->curVolume) { + *(voice->amplitudeOutput) = 0; + } - int volume = voice->curVolume - voice->releaseRate; - voice->curVolume = volume; + int volume = voice->curVolume - voice->releaseRate; + if (volume < 0) + volume = 0; - if (volume < 0) { - volume = voice->curVolume = 0; + voice->curVolume = volume; + *(voice->amplitudeOutput) = ((volume >> 4) | (volume & 0xF0)) & voice->channel; + ++_outputTableReady; } - - *(voice->amplitudeOutput) = ((volume >> 4) | (volume & 0xF0)) & voice->channel; - ++_outputTableReady; } } @@ -511,44 +517,50 @@ void Player_V2CMS::processChannel(Voice2 *channel) { } void Player_V2CMS::processRelease(Voice2 *channel) { - channel->curVolume -= channel->releaseRate; - if (channel->curVolume < 0) - channel->curVolume = 0; + int newVolume = channel->curVolume - channel->releaseRate; + if (newVolume < 0) + newVolume = 0; + + channel->curVolume = newVolume; processVibrato(channel); } void Player_V2CMS::processAttack(Voice2 *channel) { - channel->curVolume += channel->attackRate; - if (channel->curVolume >= 0) { - if (channel->curVolume <= channel->maxAmpl) - return processVibrato(channel); + int newVolume = channel->curVolume + channel->attackRate; + if (newVolume > channel->maxAmpl) { + channel->curVolume = channel->maxAmpl; + channel->nextProcessState = PROCESS_DECAY; + } else { + channel->curVolume = newVolume; } - channel->curVolume = channel->maxAmpl; - channel->nextProcessState = PROCESS_DECAY; + processVibrato(channel); } void Player_V2CMS::processDecay(Voice2 *channel) { - channel->curVolume -= channel->decayRate; - if (channel->curVolume >= 0) { - if (channel->curVolume > channel->sustainRate) - return processVibrato(channel); + int newVolume = channel->curVolume - channel->decayRate; + if (newVolume <= channel->sustainRate) { + channel->curVolume = channel->sustainRate; + channel->nextProcessState = PROCESS_SUSTAIN; + } else { + channel->curVolume = newVolume; } - channel->curVolume = channel->sustainRate; - channel->nextProcessState = PROCESS_SUSTAIN; + processVibrato(channel); } void Player_V2CMS::processSustain(Voice2 *channel) { if (channel->unkVibratoRate) { - int volume = (int)channel->curVolume + (int)channel->unkRate; + int16 volume = channel->curVolume + channel->unkRate; if (volume & 0xFF00) { - volume = ((~volume) >> 8) & 0xFF; + volume = int8(volume >> 8); + volume = -volume; } + channel->curVolume = volume; - --(channel->unkCount); + --channel->unkCount; if (!channel->unkCount) { - channel->unkRate = ~(channel->unkRate); + channel->unkRate = -channel->unkRate; channel->unkCount = (channel->unkVibratoDepth & 0x0F) << 1; } } @@ -557,12 +569,13 @@ void Player_V2CMS::processSustain(Voice2 *channel) { void Player_V2CMS::processVibrato(Voice2 *channel) { if (channel->vibratoRate) { - uint16 temp = channel->curFreq + channel->curVibratoRate; + int16 temp = channel->curFreq + channel->curVibratoRate; channel->curOctave += (temp & 0xFF00) >> 8; channel->curFreq = temp & 0xFF; - --(channel->curVibratoUnk); + + --channel->curVibratoUnk; if (!channel->curVibratoUnk) { - channel->curVibratoRate = ~(channel->curVibratoRate); + channel->curVibratoRate = -channel->curVibratoRate; channel->curVibratoUnk = (channel->vibratoDepth & 0x0F) << 1; } } @@ -572,25 +585,16 @@ void Player_V2CMS::processVibrato(Voice2 *channel) { output = channel->freqOutput; *output = channel->curFreq; output = channel->octaveOutput; - *output = ((((channel->curOctave >> 4) | (channel->curOctave & 0x0F)) & _octaveMask) | ((~_octaveMask) & *output)); + *output = ((((channel->curOctave << 4) | (channel->curOctave & 0x0F)) & _octaveMask) | ((~_octaveMask) & *output)); } void Player_V2CMS::offAllChannels() { - warning("offAllChannels STUB"); -/* - // after using this sound can not be played anymore (since it would deinit the emulator) - static const byte cmsOffData[10*2] = { - 0x1C, 0x02, - 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, - 0x14, 0x3F, 0x15, 0x00, 0x16, 0x00 - }; - for (int cmsPort = 0x220, i = 0; i < 2; cmsPort += 2, ++i) { - for (int off = 0; off < 10; ++off) { - _cmsEmu->portWrite(cmsPort+1, cmsOffData[off*2]); - _cmsEmu->portWrite(cmsPort, cmsOffData[off*2+1]); + for (int off = 1; off <= 10; ++off) { + _cmsEmu->portWrite(cmsPort+1, cmsInitData[off*2]); + _cmsEmu->portWrite(cmsPort, cmsInitData[off*2+1]); } - }*/ + } } Player_V2CMS::Voice2 *Player_V2CMS::getFreeVoice() { @@ -637,8 +641,10 @@ void Player_V2CMS::playNote(byte *&data) { freeVoice->sustainRate = voice->sustain; freeVoice->releaseRate = voice->release; freeVoice->octaveAdd = voice->octadd; - freeVoice->vibratoRate = freeVoice->curVibratoRate = voice->vibrato; - freeVoice->unkVibratoRate = freeVoice->unkRate = voice->vibrato2; + freeVoice->vibratoRate = freeVoice->curVibratoRate = voice->vibrato & 0xFF; + freeVoice->vibratoDepth = freeVoice->curVibratoUnk = voice->vibrato >> 8; + freeVoice->unkVibratoRate = freeVoice->unkRate = voice->vibrato2 & 0xFF; + freeVoice->unkVibratoDepth = freeVoice->unkCount = voice->vibrato2 >> 8; freeVoice->maxAmpl = 0xFF; uint8 rate = freeVoice->attackRate; @@ -650,7 +656,10 @@ void Player_V2CMS::playNote(byte *&data) { rate -= freeVoice->attackRate; freeVoice->curVolume = rate; freeVoice->playingNote = *data; - int octave = octaveTable[(*data + 3) << 1] + freeVoice->octaveAdd - 3; + + uint16 note = noteTable[*data + 3]; + + int octave = int8(note & 0xFF) + freeVoice->octaveAdd - 3; if (octave < 0) octave = 0; if (octave > 7) @@ -658,10 +667,10 @@ void Player_V2CMS::playNote(byte *&data) { if (!octave) ++octave; freeVoice->curOctave = octave; - freeVoice->curFreq = freqTable[volume << 2]; + freeVoice->curFreq = freqTable[(note >> 8) << 2]; freeVoice->curVolume = 0; freeVoice->nextProcessState = PROCESS_ATTACK; - if (_lastMidiCommand & 1) + if (!(_lastMidiCommand & 1)) freeVoice->channel = 0xF0; else freeVoice->channel = 0x0F; @@ -672,35 +681,27 @@ void Player_V2CMS::playNote(byte *&data) { Player_V2CMS::Voice2 *Player_V2CMS::getPlayVoice(byte param) { byte channelNum = _lastMidiCommand & 0x0F; - Voice2 *channel = _midiChannel[channelNum]; + Voice2 *curVoice = _midiChannel[channelNum]; - if (channel) { - Voice2 *backUp = 0; + if (curVoice) { + Voice2 *prevVoice = 0; while (true) { - if (channel->playingNote == param) + if (curVoice->playingNote == param) break; - backUp = channel; - channel = channel->nextVoice; - if (!channel) + prevVoice = curVoice; + curVoice = curVoice->nextVoice; + if (!curVoice) return 0; } - Voice2 *backUp2 = channel->nextVoice; - { - Voice2 *temp = backUp; - backUp = channel; - channel = temp; - } - if (channel) { - channel->nextVoice = backUp2; - } else { - _midiChannel[channelNum] = backUp2; - } - channel = backUp; + if (prevVoice) + prevVoice->nextVoice = curVoice->nextVoice; + else + _midiChannel[channelNum] = curVoice->nextVoice; } - return channel; + return curVoice; } void Player_V2CMS::clearNote(byte *&data) { diff --git a/engines/scumm/player_v2cms.h b/engines/scumm/player_v2cms.h index f7dc0c16b1..ba2c3f25d8 100644 --- a/engines/scumm/player_v2cms.h +++ b/engines/scumm/player_v2cms.h @@ -42,7 +42,7 @@ public: virtual void startSound(int sound); virtual void stopSound(int sound); virtual void stopAllSounds(); -// virtual int getMusicTimer(); + virtual int getMusicTimer(); virtual int getSoundStatus(int sound) const; // AudioStream API @@ -72,12 +72,12 @@ protected: uint8 channel; int8 sustainLevel; - int8 attackRate; + uint8 attackRate; uint8 maxAmpl; - int8 decayRate; - int8 sustainRate; - int8 releaseRate; - int8 releaseTime; + uint8 decayRate; + uint8 sustainRate; + uint8 releaseRate; + uint8 releaseTime; int8 vibratoRate; int8 vibratoDepth; @@ -91,9 +91,9 @@ protected: int8 unkCount; int nextProcessState; - int8 curVolume; - int8 curOctave; - int8 curFreq; + uint8 curVolume; + uint8 curOctave; + uint8 curFreq; int8 octaveAdd; @@ -114,8 +114,8 @@ protected: Voice2 _cmsVoices[8]; MusicChip _cmsChips[2]; - int8 _tempo; - int8 _tempoSum; + uint8 _tempo; + uint8 _tempoSum; byte _looping; byte _octaveMask; int16 _midiDelay; @@ -132,6 +132,8 @@ protected: byte _restart; byte _curSno; + int _musicTimer, _musicTimerTicks; + void loadMidiData(byte *data, int sound); void play(); @@ -147,7 +149,7 @@ protected: void clearNote(byte *&data); void offAllChannels(); void playVoice(); - void processMidiData(uint ticks); + void processMidiData(); Voice2 *getFreeVoice(); Voice2 *getPlayVoice(byte param); diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index 0f01e39459..d546f039fe 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -1754,12 +1754,8 @@ void ScummEngine::setupMusic(int midi) { case MT_PCJR: _musicType = MDT_PCJR; break; - //case MT_CMS: -#if 1 - _musicType = MDT_ADLIB; -#else - _musicType = MDT_CMS; // Still has number of bugs, disable by default -#endif + case MT_CMS: + _musicType = MDT_CMS; break; case MT_TOWNS: _musicType = MDT_TOWNS; diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp index a74fa365a2..b4836d0c31 100644 --- a/engines/scumm/sound.cpp +++ b/engines/scumm/sound.cpp @@ -2104,18 +2104,37 @@ int ScummEngine::readSoundResourceSmallHeader(ResId idx) { _fileHandle->read(_res->createResource(rtSound, idx, wa_size + 6), wa_size + 6); } return 1; - } else if (_musicType == MDT_CMS && ad_offs != 0) { + } else if (_musicType == MDT_CMS) { if (_game.features & GF_OLD_BUNDLE) { - _fileHandle->seek(wa_offs + wa_size + 6, SEEK_SET); - byte musType = _fileHandle->readByte(); + bool hasAdLibMusicTrack = false; - if (musType == 0x80) { + if (ad_offs) { + _fileHandle->seek(ad_offs + 4 + 2, SEEK_SET); + hasAdLibMusicTrack = (_fileHandle->readByte() == 0x80); + } + + if (hasAdLibMusicTrack) { _fileHandle->seek(ad_offs, SEEK_SET); _fileHandle->read(_res->createResource(rtSound, idx, ad_size), ad_size); } else { _fileHandle->seek(wa_offs, SEEK_SET); _fileHandle->read(_res->createResource(rtSound, idx, wa_size), wa_size); } + } else { + bool hasAdLibMusicTrack = false; + + if (ad_offs) { + _fileHandle->seek(ad_offs + 2, SEEK_SET); + hasAdLibMusicTrack = (_fileHandle->readByte() == 0x80); + } + + if (hasAdLibMusicTrack) { + _fileHandle->seek(ad_offs - 4, SEEK_SET); + _fileHandle->read(_res->createResource(rtSound, idx, ad_size + 4), ad_size + 4); + } else { + _fileHandle->seek(wa_offs - 6, SEEK_SET); + _fileHandle->read(_res->createResource(rtSound, idx, wa_size + 6), wa_size + 6); + } } } else if (ad_offs != 0) { // AD resources have a header, instrument definitions and one MIDI track. |