aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Pitkanen2011-05-25 12:30:44 +0300
committerEugene Sandulenko2011-08-13 23:26:19 +0100
commitab784944eac1530fa257191ee7b21a154d9f639f (patch)
tree79860d8f7ecda8889ed4ae7d5464575f371d6037
parenta6acf42e74dc49a184bab461fcc29ac9b30af8fb (diff)
downloadscummvm-rg350-ab784944eac1530fa257191ee7b21a154d9f639f.tar.gz
scummvm-rg350-ab784944eac1530fa257191ee7b21a154d9f639f.tar.bz2
scummvm-rg350-ab784944eac1530fa257191ee7b21a154d9f639f.zip
AGI: Implement note fetch routine for AGI v2.001 sound resources
I suspect this is the format for AGI V1 sound resources as well. It is currently implemented by splitting getNextNote() to getNextNote_v2() and getNextNote_v1(). Since the V1 format consists of simple register values to the sound chip in PCjr, this could probably be made more cleanly by refactoring the code to resemble the chip more closely, so that its state is updated by writing to the registers.
-rw-r--r--engines/agi/sound.cpp9
-rw-r--r--engines/agi/sound.h2
-rw-r--r--engines/agi/sound_pcjr.cpp103
-rw-r--r--engines/agi/sound_pcjr.h5
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