added rjp1 module specific pattern playback

svn-id: r29559
This commit is contained in:
Gregory Montoir 2007-11-18 20:27:31 +00:00
parent 9e58b0253d
commit c76c6e2256
4 changed files with 141 additions and 69 deletions

View File

@ -541,7 +541,7 @@ void AmigaSound::updateMusic() {
if (_fluteCount > 0 && (_lastOverride == 40 || _lastOverride == 3)) {
--_fluteCount;
if (_fluteCount == 0) {
playRandomPatternJungle();
playPattern("JUNG", 5 + _vm->randomizer.getRandomNumber(6));
_fluteCount = 100;
}
}
@ -564,8 +564,8 @@ void AmigaSound::playSound(const char *base) {
}
}
void AmigaSound::playModule(const char *base, int song) {
debug(7, "AmigaSound::playModule(%s, %d)", base, song);
Audio::AudioStream *AmigaSound::loadModule(const char *base, int num) {
debug(7, "AmigaSound::loadModule(%s, %d)", base, num);
char name[20];
// load song/pattern data
@ -580,20 +580,29 @@ void AmigaSound::playModule(const char *base, int song) {
uint8 *insData = _vm->resource()->loadFile(name, 0, &insDataSize);
Common::MemoryReadStream insStr(insData, insDataSize);
_mixer->stopHandle(_modHandle);
Audio::AudioStream *stream = Audio::makeRjp1Stream(&sngStr, &insStr, song, _mixer->getOutputRate());
if (stream) {
_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_modHandle, stream);
}
Audio::AudioStream *stream = Audio::makeRjp1Stream(&sngStr, &insStr, num, _mixer->getOutputRate());
delete[] sngData;
delete[] insData;
return stream;
}
void AmigaSound::playModule(const char *base, int song) {
_mixer->stopHandle(_modHandle);
Audio::AudioStream *stream = loadModule(base, song);
if (stream) {
_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_modHandle, stream);
}
_fanfareCount = 0;
}
void AmigaSound::playRandomPatternJungle() {
// XXX pickup a pattern (songData[4],songData[6]) between 5 and 11 from JUNG.SNG and play it
void AmigaSound::playPattern(const char *base, int pattern) {
_mixer->stopHandle(_patHandle);
Audio::AudioStream *stream = loadModule(base, -pattern);
if (stream) {
_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_patHandle, stream);
}
}
bool AmigaSound::playSpecialSfx(int16 sfx) {

View File

@ -170,13 +170,15 @@ public:
protected:
void playSound(const char *base);
Audio::AudioStream *loadModule(const char *base, int song);
void playModule(const char *base, int song);
void playRandomPatternJungle();
void playPattern(const char *base, int pattern);
bool playSpecialSfx(int16 sfx);
int16 _fanfareRestore;
int _fanfareCount, _fluteCount;
Audio::SoundHandle _modHandle;
Audio::SoundHandle _patHandle;
Audio::SoundHandle _sfxHandle;
};

View File

@ -70,6 +70,7 @@ struct Rjp1Channel {
uint16 len;
uint16 repeatPos;
uint16 repeatLen;
bool isSfx;
};
class Rjp1 : public Paula {
@ -90,6 +91,7 @@ public:
bool load(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData);
void unload();
void startPattern(int ch, int pat);
void startSong(int song);
protected:
@ -98,6 +100,8 @@ protected:
void turnOffChannel(Rjp1Channel *channel);
void playChannel(Rjp1Channel *channel);
void turnOnChannel(Rjp1Channel *channel);
bool executeSfxSequenceOp(Rjp1Channel *channel, uint8 code, const uint8 *&p);
bool executeSongSequenceOp(Rjp1Channel *channel, uint8 code, const uint8 *&p);
void playSongSequence(Rjp1Channel *channel);
void modulateVolume(Rjp1Channel *channel);
void modulatePeriod(Rjp1Channel *channel);
@ -186,6 +190,18 @@ void Rjp1::unload() {
memset(_channelsTable, 0, sizeof(_channelsTable));
}
void Rjp1::startPattern(int ch, int pat) {
Rjp1Channel *channel = &_channelsTable[ch];
_vars.activeChannelsMask |= 1 << ch;
channel->sequenceData = READ_BE_UINT32(_vars.songData[4] + pat * 4) + _vars.songData[6];
channel->loopSeqCount = 6;
channel->loopSeqCur = channel->loopSeq2Cur = 1;
channel->active = true;
channel->isSfx = true;
// "start" Paula audiostream
startPaula();
}
void Rjp1::startSong(int song) {
if (song == 0 || song >= _vars.subsongsCount) {
warning("Invalid subsong number %d, defaulting to 1", song);
@ -241,6 +257,98 @@ void Rjp1::turnOnChannel(Rjp1Channel *channel) {
}
}
bool Rjp1::executeSfxSequenceOp(Rjp1Channel *channel, uint8 code, const uint8 *&p) {
bool loop = true;
switch (code & 7) {
case 0:
_vars.activeChannelsMask &= ~(1 << _vars.currentChannel);
loop = false;
stopPaula();
break;
case 1:
setRelease(channel);
loop = false;
break;
case 2:
channel->loopSeqCount = *p++;
break;
case 3:
channel->loopSeq2Count = *p++;
break;
case 4:
code = *p++;
if (code != 0) {
setupInstrument(channel, code);
}
break;
case 7:
loop = false;
break;
}
return loop;
}
bool Rjp1::executeSongSequenceOp(Rjp1Channel *channel, uint8 code, const uint8 *&p) {
bool loop = true;
const uint8 *offs;
switch (code & 7) {
case 0:
offs = channel->sequenceOffsets;
channel->loopSeq2Count = 1;
while (1) {
code = *offs++;
if (code != 0) {
channel->sequenceOffsets = offs;
p = READ_BE_UINT32(_vars.songData[4] + code * 4) + _vars.songData[6];
break;
} else {
code = offs[0];
if (code == 0) {
p = 0;
channel->active = false;
_vars.activeChannelsMask &= ~(1 << _vars.currentChannel);
loop = false;
break;
} else if (code & 0x80) {
code = offs[1];
offs = READ_BE_UINT32(_vars.songData[3] + code * 4) + _vars.songData[5];
} else {
offs -= code;
}
}
}
break;
case 1:
setRelease(channel);
loop = false;
break;
case 2:
channel->loopSeqCount = *p++;
break;
case 3:
channel->loopSeq2Count = *p++;
break;
case 4:
code = *p++;
if (code != 0) {
setupInstrument(channel, code);
}
break;
case 5:
channel->volumeScale = *p++;
break;
case 6:
channel->freqStep = *p++;
channel->freqInc = READ_BE_UINT32(p); p += 4;
channel->freqInit = 0;
break;
case 7:
loop = false;
break;
}
return loop;
}
void Rjp1::playSongSequence(Rjp1Channel *channel) {
const uint8 *p = channel->sequenceData;
--channel->loopSeqCur;
@ -251,61 +359,10 @@ void Rjp1::playSongSequence(Rjp1Channel *channel) {
do {
uint8 code = *p++;
if (code & 0x80) {
const uint8 *offs;
switch (code & 7) {
case 0:
offs = channel->sequenceOffsets;
channel->loopSeq2Count = 1;
while (1) {
code = *offs++;
if (code != 0) {
channel->sequenceOffsets = offs;
p = READ_BE_UINT32(_vars.songData[4] + code * 4) + _vars.songData[6];
break;
} else {
code = offs[0];
if (code == 0) {
p = 0;
channel->active = false;
_vars.activeChannelsMask &= ~(1 << _vars.currentChannel);
loop = false;
break;
} else if (code & 0x80) {
code = offs[1];
offs = READ_BE_UINT32(_vars.songData[3] + code * 4) + _vars.songData[5];
} else {
offs -= code;
}
}
}
break;
case 1:
setRelease(channel);
loop = false;
break;
case 2:
channel->loopSeqCount = *p++;
break;
case 3:
channel->loopSeq2Count = *p++;
break;
case 4:
code = *p++;
if (code != 0) {
setupInstrument(channel, code);
}
break;
case 5:
channel->volumeScale = *p++;
break;
case 6:
channel->freqStep = *p++;
channel->freqInc = READ_BE_UINT32(p); p += 4;
channel->freqInit = 0;
break;
case 7:
loop = false;
break;
if (channel->isSfx) {
loop = executeSfxSequenceOp(channel, code, p);
} else {
loop = executeSongSequenceOp(channel, code, p);
}
} else {
code >>= 1;
@ -507,10 +564,14 @@ const int16 Rjp1::_periodsTable[] = {
const int Rjp1::_periodsCount = ARRAYSIZE(_periodsTable);
AudioStream *makeRjp1Stream(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData, int song, int rate, bool stereo) {
AudioStream *makeRjp1Stream(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData, int num, int rate, bool stereo) {
Rjp1 *stream = new Rjp1(rate, stereo);
if (stream->load(songData, instrumentsData)) {
stream->startSong(song);
if (num < 0) {
stream->startPattern(3, -num);
} else {
stream->startSong(num);
}
return stream;
}
delete stream;

View File

@ -32,7 +32,7 @@ namespace Audio {
class AudioStream;
AudioStream *makeRjp1Stream(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData, int song, int rate = 44100, bool stereo = true);
AudioStream *makeRjp1Stream(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData, int num, int rate = 44100, bool stereo = true);
} // End of namespace Audio