diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/agi/sound.cpp | 9 | ||||
-rw-r--r-- | engines/agi/sound.h | 2 | ||||
-rw-r--r-- | engines/agi/sound_pcjr.cpp | 103 | ||||
-rw-r--r-- | engines/agi/sound_pcjr.h | 5 |
4 files changed, 118 insertions, 1 deletions
diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp index f2d7af32da..f44b34c70d 100644 --- a/engines/agi/sound.cpp +++ b/engines/agi/sound.cpp @@ -41,6 +41,10 @@ AgiSound *AgiSound::createFromRawResource(uint8 *data, uint32 len, int resnum, S return NULL; uint16 type = READ_LE_UINT16(data); + // For V1 sound resources + if ((type & 0xFF) == 0x01) + return new PCjrSound(data, len, resnum, manager); + switch (type) { // Create a sound object based on the type case AGI_SOUND_SAMPLE: return new IIgsSample(data, len, resnum, manager); @@ -62,6 +66,11 @@ PCjrSound::PCjrSound(uint8 *data, uint32 len, int resnum, SoundMgr &manager) : A _data = data; // Save the resource pointer _len = len; // Save the resource's length _type = READ_LE_UINT16(data); // Read sound resource's type + + // Detect V1 sound resources + if ((_type & 0xFF) == 0x01) + _type = AGI_SOUND_4CHN; + _isValid = (_type == AGI_SOUND_4CHN) && (_data != NULL) && (_len >= 2); if (!_isValid) // Check for errors diff --git a/engines/agi/sound.h b/engines/agi/sound.h index 0ee19878c4..bd175d3c24 100644 --- a/engines/agi/sound.h +++ b/engines/agi/sound.h @@ -122,6 +122,8 @@ public: ~PCjrSound() { free(_data); } virtual uint16 type() { return _type; } const uint8 *getVoicePointer(uint voiceNum); + uint8 *getData() { return _data; } + uint32 getLength() { return _len; } protected: uint8 *_data; ///< Raw sound resource data uint32 _len; ///< Length of the raw sound resource diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp index fdebf16b1a..f5cb5e7e1b 100644 --- a/engines/agi/sound_pcjr.cpp +++ b/engines/agi/sound_pcjr.cpp @@ -153,6 +153,9 @@ void SoundGenPCJr::play(int resnum) { _tchannel[i].genType = kGenTone; _tchannel[i].genTypePrev = -1; } + + _v1data = pcjrSound->getData() + 1; + _v1size = pcjrSound->getLength() - 1; } void SoundGenPCJr::stop(void) { @@ -214,11 +217,22 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) { return attenuation; } +int SoundGenPCJr::getNextNote(int ch, Tone *tone) +{ + if (_vm->getVersion() > 0x2001) + return getNextNote_v2(ch, tone); + else + return getNextNote_v1(ch, tone); + + return -1; +} + // read the next channel data.. fill it in *tone // if tone isn't touched.. it should be inited so it just plays silence // return 0 if it's passing more data // return -1 if it's passing nothing (end of data) -int SoundGenPCJr::getNextNote(int ch, Tone *tone) { + +int SoundGenPCJr::getNextNote_v2(int ch, Tone *tone) { ToneChan *tpcm; SndGenChan *chan; const byte *data; @@ -305,6 +319,89 @@ int SoundGenPCJr::getNextNote(int ch, Tone *tone) { return 0; } +int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone) +{ + static bool fetched[4] = { false, false, false, false }; + static int duration = 0; + + // Get previously fetched data if possible + if (fetched[ch]) { + fetched[ch] = false; + + tone->freqCount = _channel[ch].freqCount; + tone->atten = _channel[ch].attenuation; + tone->type = _channel[ch].genType; + + return 0; + } + + // In the V1 player the default duration for a row is 2 ticks + if (duration > 0) { + duration--; + + tone->freqCount = _channel[ch].freqCount; + tone->atten = _channel[ch].attenuation; + tone->type = _channel[ch].genType; + + return 0; + } + duration = 2 * CHAN_MAX; + + // Otherwise fetch a row of data for all channels + byte *data = _v1data; + uint32 len = _v1size; + int reg = 0; + + if (len <= 0 || data == NULL) + return -1; + + fetched[0] = fetched[1] = fetched[2] = fetched[3] = true; + + while (*data) { + if ((*data & 0x90) == 0x90) { + reg = (*data >> 5) & 0x3; + _channel[reg].attenuation = *data & 0xF; + } else if ((*data & 0xF0) == 0xE0) { + _channel[3].genType = (data[3] & 0x4) ? kGenWhite : kGenPeriod; + int noiseFreq = data[3] & 0x03; + switch (noiseFreq) { + case 0: + _channel[3].freqCount = 32; + break; + case 1: + _channel[3].freqCount = 64; + break; + case 2: + _channel[3].freqCount = 128; + break; + case 3: + _channel[3].freqCount = _channel[2].freqCount * 2; + break; + } + } else if (*data & 0x80) { + reg = (*data >> 5) & 0x3; + _channel[reg].freqCount = *data & 0xF; + _channel[reg].genType = kGenTone; + } else { + _channel[reg].freqCount |= (*data & 0x3F) << 4; + } + + data++; + len--; + } + data++; + len--; + + _v1data = data; + _v1size = len; + + tone->freqCount = _channel[ch].freqCount; + tone->atten = _channel[ch].attenuation; + tone->type = _channel[ch].genType; + + return 0; +} + // Formulas for noise generator // bit0 = output @@ -348,9 +445,13 @@ int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) { retVal = -1; + debugC(5, kDebugLevelSound, "chanGen()"); + while (len > 0) { if (tpcm->noteCount <= 0) { // get new tone data + tpcm->avail=1; + debugC(5, kDebugLevelSound, "new note data (avail=%d)", tpcm->avail); toneNew.freqCount = 0; toneNew.atten = 0xF; toneNew.type = kGenTone; diff --git a/engines/agi/sound_pcjr.h b/engines/agi/sound_pcjr.h index 4317e86516..d9ced4ac80 100644 --- a/engines/agi/sound_pcjr.h +++ b/engines/agi/sound_pcjr.h @@ -103,6 +103,8 @@ public: private: int getNextNote(int ch, Tone *tone); + int getNextNote_v2(int ch, Tone *tone); + int getNextNote_v1(int ch, Tone *tone); int volumeCalc(SndGenChan *chan); int chanGen(int chan, int16 *stream, int len); @@ -117,6 +119,9 @@ private: int _chanAllocated; int _dissolveMethod; + + uint8 *_v1data; + uint32 _v1size; }; } // End of namespace Agi |