aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
authorFlorian Kagerer2008-06-29 15:25:45 +0000
committerFlorian Kagerer2008-06-29 15:25:45 +0000
commitb0e22db7a89a27a7f9c09870fded7a64042293c7 (patch)
tree166a00a78c24c489d6a3dc8634bab0b4e728210d /engines/kyra
parent20a50f523ebda59afb24badf12dd3b88b92702ff (diff)
downloadscummvm-rg350-b0e22db7a89a27a7f9c09870fded7a64042293c7.tar.gz
scummvm-rg350-b0e22db7a89a27a7f9c09870fded7a64042293c7.tar.bz2
scummvm-rg350-b0e22db7a89a27a7f9c09870fded7a64042293c7.zip
- some more work on the Hof FM-Towns/PC98 music driver
- move channels to a separate class svn-id: r32841
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/detection.cpp2
-rw-r--r--engines/kyra/sound.h4
-rw-r--r--engines/kyra/sound_towns.cpp1791
3 files changed, 1057 insertions, 740 deletions
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index 1e174bdfcf..3fb62b51bd 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -346,7 +346,7 @@ const KYRAGameDescription adGameDescs[] = {
KYRA2_FLOPPY_CMP_FLAGS
},
- { // // Floppy version extracted
+ { // Floppy version extracted
{
"kyra2",
"Extracted",
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index c08c531ab9..cebfdf491f 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -486,11 +486,13 @@ public:
void beginFadeOut();
int32 voicePlay(const char *file, bool isSfx = false);
- void playSoundEffect(uint8) {}
+ void playSoundEffect(uint8 track);
protected:
Audio::AudioStream *_currentSFX;
int _lastTrack;
+ bool _useFmSfx;
+
uint8 *_musicTrackData;
TownsPC98_OpnDriver *_driver;
};
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 92e39fc769..4a8e8a5b15 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -1100,7 +1100,7 @@ public:
void frequency(int freq);
void updatePhaseIncrement();
void recalculateRates();
- void generateOutput(int phasebuf, int *feedbuf, int &out);
+ void generateOutput(int phasebuf, int *_feedbuf, int &out);
void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; }
void detune(int value) { _detn = &_detnTbl[value << 5]; }
@@ -1209,7 +1209,7 @@ void TownsPC98_OpnOperator::recalculateRates() {
fs_r.shift = _rshiftTbl[r + k];
}
-void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *feedbuf, int &out) {
+void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *_feedbuf, int &out) {
if (_state == s_ready)
return;
@@ -1269,10 +1269,10 @@ void TownsPC98_OpnOperator::generateOutput(int phasebuf, int *feedbuf, int &out)
int *i = &outp, *o = &outp;
int phaseShift = 0;
- if (feedbuf) {
- o = &feedbuf[0];
- i = &feedbuf[1];
- phaseShift = _feedbackLevel ? ((feedbuf[0] + feedbuf[1]) << _feedbackLevel) : 0;
+ if (_feedbuf) {
+ o = &_feedbuf[0];
+ i = &_feedbuf[1];
+ phaseShift = _feedbackLevel ? ((_feedbuf[0] + _feedbuf[1]) << _feedbackLevel) : 0;
if (phasebuf == -1)
*i = 0;
*o = *i;
@@ -1329,7 +1329,121 @@ bool TownsPC98_OpnOperator::scaleRate(uint8 value) {
return false;
}
+class TownsPC98_OpnDriver;
+class TownsPC98_OpnChannel {
+public:
+ TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
+ uint8 key, uint8 prt, uint8 id);
+ ~TownsPC98_OpnChannel();
+ virtual void init();
+
+ typedef bool (TownsPC98_OpnChannel::*ControlEventFunc)(uint8 para);
+
+ typedef enum channelState {
+ CHS_RECALCFREQ = 0x01,
+ CHS_KEYOFF = 0x02,
+ CHS_SSG = 0x04,
+ CHS_PITCHWHEELOFF = 0x08,
+ CHS_ALL_BUT_EOT = 0x0f,
+ CHS_EOT = 0x80
+ } ChannelState;
+
+ void loadData(uint8 *data);
+ virtual void processEvents();
+ virtual void processFrequency();
+ bool processControlEvent(uint8 cmd);
+ void writeReg(uint8 regAdress, uint8 value);
+
+ virtual void keyOn();
+ virtual void keyOff();
+
+ void setOutputLevel();
+ void fadeStep();
+ void reset();
+
+ void updateEnv();
+ void generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed);
+
+ bool _enableLeft;
+ bool _enableRight;
+ bool _fading;
+ bool _updateEnvelopes;
+ const uint8 _idFlag;
+ int _feedbuf[3];
+
+protected:
+ bool control_dummy(uint8 para);
+ bool control_f0_setPatch(uint8 para);
+ bool control_f1_presetOutputLevel(uint8 para);
+ bool control_f2_setKeyOffTime(uint8 para);
+ bool control_f3_setFreqLSB(uint8 para);
+ bool control_f4_setOutputLevel(uint8 para);
+ bool control_f5_setTempo(uint8 para);
+ bool control_f6_repeatSection(uint8 para);
+ bool control_f7_setupPitchWheel(uint8 para);
+ bool control_f8_togglePitchWheel(uint8 para);
+ bool control_fa_writeReg(uint8 para);
+ bool control_fb_incOutLevel(uint8 para);
+ bool control_fc_decOutLevel(uint8 para);
+ bool control_fd_jump(uint8 para);
+ bool control_ff_endOfTrack(uint8 para);
+
+ bool control_f0_setPatchSSG(uint8 para);
+ bool control_f1_setTotalLevel(uint8 para);
+ bool control_f4_setAlgorithm(uint8 para);
+ bool control_f9_unkSSG(uint8 para);
+ bool control_fb_incOutLevelSSG(uint8 para);
+ bool control_fc_decOutLevelSSG(uint8 para);
+ bool control_ff_endOfTrackSSG(uint8 para);
+
+ uint8 _ticksLeft;
+ uint8 _algorithm;
+ uint8 _instrID;
+ uint8 _totalLevel;
+ uint8 _frqBlockMSB;
+ int8 _frqLSB;
+ uint8 _keyOffTime;
+ bool _protect;
+ uint8 *_dataPtr;
+ uint8 _unk15, _unk16;
+ uint8 _ptchWhlInitDelayLo;
+ uint8 _ptchWhlInitDelayHi;
+ int16 _ptchWhlModInitVal;
+ uint8 _ptchWhlDuration;
+ uint8 _ptchWhlCurDelay;
+ int16 _ptchWhlModCurVal;
+ uint8 _ptchWhlDurLeft;
+ uint16 frequency;
+ uint8 _unk28, _unk29;
+ uint8 _regOffset;
+ uint8 _flags;
+ const uint8 _chanNum;
+ const uint8 _keyNum;
+ const uint8 _part;
+
+ TownsPC98_OpnDriver *_drv;
+ TownsPC98_OpnOperator **_opr;
+ uint16 _frqTemp;
+
+ const ControlEventFunc *controlEvents;
+};
+
+class TownsPC98_OpnChannelSSG : public TownsPC98_OpnChannel {
+public:
+ TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs,
+ uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
+ void init();
+
+ void processEvents();
+ void processFrequency();
+
+ void keyOn();
+ void keyOff();
+};
+
class TownsPC98_OpnDriver : public Audio::AudioStream {
+friend class TownsPC98_OpnChannel;
+friend class TownsPC98_OpnChannelSSG;
public:
enum OpnType {
OD_TOWNS,
@@ -1362,92 +1476,23 @@ public:
protected:
void generateTables();
- typedef enum channelState {
- CHS_RECALCFREQ = 0x01,
- CHS_KEYOFF = 0x02,
- CHS_PITCHWHEELOFF = 0x08,
- CHS_ALL_BUT_EOT = 0x0f,
- CHS_EOT = 0x80
- } ChannelState;
+ TownsPC98_OpnChannel **_channels;
+ TownsPC98_OpnChannelSSG **_ssgChannels;
+ //TownsPC98_OpnChannel *_adpcmChannel;
- struct TwnChannel {
- uint8 ticksLeft;
- uint8 unk1, unk2, unk3;
- uint8 algorithm;
- uint8 instrID;
- uint8 totalLevel;
- uint8 frqBlockMSB;
- int8 frqLSB;
- uint8 keyOffTime;
- bool protect;
- uint8 *dataPtr;
- uint8 unk15, unk16;
- uint8 ptchWhlInitDelayLo;
- uint8 ptchWhlInitDelayHi;
- int16 ptchWhlModInitVal;
- uint8 ptchWhlDuration;
- uint8 ptchWhlCurDelay;
- int16 ptchWhlModCurVal;
- uint8 ptchWhlDurLeft;
- uint16 frequency;
- uint8 unk28, unk29;
- uint8 regOffset;
- uint8 flags;
- uint8 chanNum;
- uint8 keyNum;
- uint8 part;
- uint8 idFlag;
-
- TownsPC98_OpnOperator *opr[4];
- uint16 frqTemp;
- bool enableLeft;
- bool enableRight;
- bool updateEnvelopes;
- int feedbuf[3];
- } **_channels;
-
- void processEvents(TwnChannel *chan);
- void processFrequency(TwnChannel *chan);
- bool processControlEvent(TwnChannel *chan, uint8 cmd);
-
- void setOutputLevel(TwnChannel *chan);
void setTempo(uint8 tempo);
- void keyOn(TwnChannel *chan);
- void keyOff(TwnChannel *chan);
- void writeReg(TwnChannel *chan, uint8 regAdress, uint8 value);
-
void lock() { _mutex.lock(); }
void unlock() { _mutex.unlock(); }
- bool control_f0_setPatch(TwnChannel *chan, uint8 para);
- bool control_f1_presetOutputLevel(TwnChannel *chan, uint8 para);
- bool control_f2_setKeyOffTime(TwnChannel *chan, uint8 para);
- bool control_f3_setFreqLSB(TwnChannel *chan, uint8 para);
- bool control_f4_setOutputLevel(TwnChannel *chan, uint8 para);
- bool control_f5_setTempo(TwnChannel *chan, uint8 para);
- bool control_f6_repeatSection(TwnChannel *chan, uint8 para);
- bool control_f7_setupPitchWheel(TwnChannel *chan, uint8 para);
- bool control_f8_togglePitchWheel(TwnChannel *chan, uint8 para);
- bool control_f9_unk(TwnChannel *chan, uint8 para);
- bool control_fa_writeReg(TwnChannel *chan, uint8 para);
- bool control_fb_incOutLevel(TwnChannel *chan, uint8 para);
- bool control_fc_decOutLevel(TwnChannel *chan, uint8 para);
- bool control_fd_jump(TwnChannel *chan, uint8 para);
- bool control_fe_unk(TwnChannel *chan, uint8 para);
- bool control_ff_endOfTrack(TwnChannel *chan, uint8 para);
-
- typedef bool (TownsPC98_OpnDriver::*ControlEventFunc)(TwnChannel * chan, uint8 para);
-
Audio::Mixer *_mixer;
- TownsPC98_OpnOperator **_operators;
Common::Mutex _mutex;
Audio::SoundHandle _soundHandle;
- const uint8 *_twnCarrier;
- const uint8 *_twnFreqTable;
- const uint8 *_twnFxCmdLen;
- const uint8 *_twnLvlPresets;
+ const uint8 *_opnCarrier;
+ const uint8 *_opnFreqTable;
+ const uint8 *_opnFxCmdLen;
+ const uint8 *_opnLvlPresets;
uint8 *_oprRates;
uint8 *_oprRateshift;
@@ -1465,11 +1510,10 @@ protected:
uint8 _finishedChannelsFlag;
uint16 _tempo;
bool _playing;
- bool _fading;
uint8 _looping;
uint32 _tickCounter;
- bool _updateEnvelopes;
+ bool __updateEnvelopes;
int32 _samplesTillCallback;
int32 _samplesTillCallbackRemainder;
@@ -1484,15 +1528,820 @@ protected:
double _baserate;
static const uint8 _drvTables[];
static const uint32 _adtStat[];
+ bool _ready;
};
+TownsPC98_OpnChannel::TownsPC98_OpnChannel(TownsPC98_OpnDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
+ uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key),
+ _part(prt), _idFlag(id) {
+
+ _ticksLeft = _algorithm = _instrID = _totalLevel = _frqBlockMSB = _keyOffTime = _unk15 = _unk16 = 0;
+ _ptchWhlInitDelayLo = _ptchWhlInitDelayHi = _ptchWhlDuration = _ptchWhlCurDelay = _ptchWhlDurLeft = _unk28 = _unk29 = 0;
+ _frqLSB = 0;
+ _protect = _updateEnvelopes = _fading = false;
+ _enableLeft = _enableRight = true;
+ _dataPtr = 0;
+ _ptchWhlModInitVal = _ptchWhlModCurVal = 0;
+ frequency = _frqTemp = 0;
+ memset(&_feedbuf, 0, sizeof(int) * 3);
+ _opr = 0;
+}
+
+TownsPC98_OpnChannel::~TownsPC98_OpnChannel() {
+ if (_opr) {
+ for (int i = 0; i < 4; i++)
+ delete _opr[i];
+ delete [] _opr;
+ }
+}
+
+void TownsPC98_OpnChannel::init() {
+
+ _opr = new TownsPC98_OpnOperator*[4];
+ for (int i = 0; i < 4; i++)
+ _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift,
+ _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune);
+
+ #define Control(x) &TownsPC98_OpnChannel::control_##x
+ static const ControlEventFunc ctrlEvents[] = {
+ Control(f0_setPatch),
+ Control(f1_presetOutputLevel),
+ Control(f2_setKeyOffTime),
+ Control(f3_setFreqLSB),
+ Control(f4_setOutputLevel),
+ Control(f5_setTempo),
+ Control(f6_repeatSection),
+ Control(f7_setupPitchWheel),
+ Control(f8_togglePitchWheel),
+ Control(dummy),
+ Control(fa_writeReg),
+ Control(fb_incOutLevel),
+ Control(fc_decOutLevel),
+ Control(fd_jump),
+ Control(dummy),
+ Control(ff_endOfTrack)
+ };
+ #undef Control
+
+ controlEvents = ctrlEvents;
+}
+
+void TownsPC98_OpnChannel::keyOff() {
+ // all operators off
+ uint8 value = _keyNum & 0x0f;
+ uint8 regAdress = 0x28;
+ writeReg(regAdress, value);
+ _flags |= CHS_KEYOFF;
+}
+
+void TownsPC98_OpnChannel::keyOn() {
+ // all operators on
+ uint8 value = _keyNum | 0xf0;
+ uint8 regAdress = 0x28;
+ writeReg(regAdress, value);
+}
+
+
+void TownsPC98_OpnChannel::loadData(uint8 *data) {
+ _flags = (_flags & ~CHS_EOT) | CHS_ALL_BUT_EOT;
+ _ticksLeft = 1;
+ _dataPtr = data;
+ _totalLevel = 0x7F;
+
+ uint8 *src_b = _dataPtr;
+ int loop = 1;
+ uint8 cmd = 0;
+ while (loop) {
+ if (loop == 1) {
+ cmd = *src_b++;
+ if (cmd < 0xf0) {
+ src_b++;
+ loop = 1;
+ } else {
+ if (cmd == 0xff) {
+ loop = *src_b ? 2 : 0;
+ if (READ_LE_UINT16(src_b))
+ _drv->_looping |= _idFlag;
+ } else if (cmd == 0xf6) {
+ loop = 3;
+ } else {
+ loop = 2;
+ }
+ }
+ } else if (loop == 2) {
+ src_b += _drv->_opnFxCmdLen[cmd - 240];
+ loop = 1;
+ } else if (loop == 3) {
+ src_b[0] = src_b[1];
+ src_b += 4;
+ loop = 1;
+ }
+ }
+}
+
+void TownsPC98_OpnChannel::processEvents() {
+ if (_flags & CHS_EOT)
+ return;
+
+ if (_protect == false && _ticksLeft == _keyOffTime)
+ keyOff();
+
+ if (--_ticksLeft)
+ return;
+
+ if (_protect == false)
+ keyOff();
+
+ uint8 cmd = 0;
+ bool loop = true;
+
+ while (loop) {
+ cmd = *_dataPtr++;
+ if (cmd < 0xf0)
+ loop = false;
+ else if (!processControlEvent(cmd))
+ return;
+ }
+
+ uint8 para = *_dataPtr++;
+
+ if (cmd == 0x80) {
+ keyOff();
+ _protect = false;
+ } else {
+ keyOn();
+
+ if (_protect == false || cmd != _frqBlockMSB)
+ _flags |= CHS_RECALCFREQ;
+
+ _protect = (para & 0x80) ? true : false;
+ _frqBlockMSB = cmd;
+ }
+
+ _ticksLeft = para & 0x7f;
+}
+
+void TownsPC98_OpnChannel::processFrequency() {
+ if (_flags & CHS_RECALCFREQ) {
+ uint8 block = (_frqBlockMSB & 0x70) >> 1;
+ uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f];
+ frequency = (bfreq + _frqLSB) | (block << 8);
+
+ writeReg(_regOffset + 0xa4, (frequency >> 8));
+ writeReg(_regOffset + 0xa0, (frequency & 0xff));
+
+ _ptchWhlCurDelay = _ptchWhlInitDelayHi;
+ if (_flags & CHS_KEYOFF) {
+ _ptchWhlModCurVal = _ptchWhlModInitVal;
+ _ptchWhlCurDelay += _ptchWhlInitDelayLo;
+ }
+
+ _ptchWhlDurLeft = (_ptchWhlDuration >> 1);
+ _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ);
+ }
+
+ if (!(_flags & CHS_PITCHWHEELOFF)) {
+ if (--_ptchWhlCurDelay)
+ return;
+ _ptchWhlCurDelay = _ptchWhlInitDelayHi;
+ frequency += _ptchWhlModCurVal;
+
+ writeReg(_regOffset + 0xa4, (frequency >> 8));
+ writeReg(_regOffset + 0xa0, (frequency & 0xff));
+
+ if(!--_ptchWhlDurLeft) {
+ _ptchWhlDurLeft = _ptchWhlDuration;
+ _ptchWhlModCurVal = -_ptchWhlModCurVal;
+ }
+ }
+}
+
+bool TownsPC98_OpnChannel::processControlEvent(uint8 cmd) {
+ uint8 para = *_dataPtr++;
+ return (this->*controlEvents[cmd & 0x0f])(para);
+}
+
+void TownsPC98_OpnChannel::setOutputLevel() {
+ uint8 outopr = _drv->_opnCarrier[_algorithm];
+ uint8 reg = 0x40 + _regOffset;
+
+ for (int i = 0; i < 4; i++) {
+ if (outopr & 1)
+ writeReg(reg, _totalLevel);
+ outopr >>= 1;
+ reg += 4;
+ }
+}
+
+void TownsPC98_OpnChannel::fadeStep() {
+ _totalLevel += 3;
+ if (_totalLevel > 0x7f)
+ _totalLevel = 0x7f;
+ setOutputLevel();
+}
+
+void TownsPC98_OpnChannel::reset() {
+ for (int i = 0; i < 4; i++)
+ _opr[i]->reset();
+
+ _fading = _updateEnvelopes = false;
+ _enableLeft = _enableRight = true;
+ memset(&_feedbuf, 0, sizeof(int) * 3);
+}
+
+void TownsPC98_OpnChannel::updateEnv() {
+ for (int i = 0; i < 4 ; i++)
+ _opr[i]->updatePhaseIncrement();
+}
+
+void TownsPC98_OpnChannel::generateOutput(int16 &leftSample, int16 &rightSample, int *del, int *feed) {
+ int phbuf1, phbuf2, output;
+ phbuf1 = phbuf2 = output = 0;
+
+ switch (_algorithm) {
+ case 0:
+ _opr[0]->generateOutput(0, feed, phbuf1);
+ _opr[2]->generateOutput(*del, 0, phbuf2);
+ *del = 0;
+ _opr[1]->generateOutput(phbuf1, 0, *del);
+ _opr[3]->generateOutput(phbuf2, 0, output);
+ break;
+ case 1:
+ _opr[0]->generateOutput(0, feed, phbuf1);
+ _opr[2]->generateOutput(*del, 0, phbuf2);
+ _opr[1]->generateOutput(0, 0, phbuf1);
+ _opr[3]->generateOutput(phbuf2, 0, output);
+ *del = phbuf1;
+ break;
+ case 2:
+ _opr[0]->generateOutput(0, feed, phbuf2);
+ _opr[2]->generateOutput(*del, 0, phbuf2);
+ _opr[1]->generateOutput(0, 0, phbuf1);
+ _opr[3]->generateOutput(phbuf2, 0, output);
+ *del = phbuf1;
+ break;
+ case 3:
+ _opr[0]->generateOutput(0, feed, phbuf2);
+ _opr[2]->generateOutput(0, 0, *del);
+ _opr[1]->generateOutput(phbuf2, 0, phbuf1);
+ _opr[3]->generateOutput(*del, 0, output);
+ *del = phbuf1;
+ break;
+ case 4:
+ _opr[0]->generateOutput(0, feed, phbuf1);
+ _opr[2]->generateOutput(0, 0, phbuf2);
+ _opr[1]->generateOutput(phbuf1, 0, output);
+ _opr[3]->generateOutput(phbuf2, 0, output);
+ *del = 0;
+ break;
+ case 5:
+ *del = feed[1];
+ _opr[0]->generateOutput(-1, feed, phbuf1);
+ _opr[2]->generateOutput(*del, 0, output);
+ _opr[1]->generateOutput(*del, 0, output);
+ _opr[3]->generateOutput(*del, 0, output);
+ break;
+ case 6:
+ _opr[0]->generateOutput(0, feed, phbuf1);
+ _opr[2]->generateOutput(0, 0, output);
+ _opr[1]->generateOutput(phbuf1, 0, output);
+ _opr[3]->generateOutput(0, 0, output);
+ *del = 0;
+ break;
+ case 7:
+ _opr[0]->generateOutput(0, feed, output);
+ _opr[2]->generateOutput(0, 0, output);
+ _opr[1]->generateOutput(0, 0, output);
+ _opr[3]->generateOutput(0, 0, output);
+ *del = 0;
+ break;
+ };
+
+ if (_enableLeft) {
+ int l = output + leftSample;
+ if (l > 32767)
+ l = 32767;
+ if (l < -32767)
+ l = -32767;
+ leftSample = (int16) l;
+ }
+
+ if (_enableRight) {
+ int r = output + rightSample;
+ if (r > 32767)
+ r = 32767;
+ if (r < -32767)
+ r = -32767;
+ rightSample = (int16) r;
+ }
+}
+
+void TownsPC98_OpnChannel::writeReg(uint8 regAdress, uint8 value) {
+ uint8 h = regAdress & 0xf0;
+ uint8 l = (regAdress & 0x0f);
+ static const uint8 oprOrdr[] = { 0, 2, 1, 3 };
+ uint8 o = oprOrdr[(l - _regOffset) >> 2];
+
+ switch (h) {
+ case 0x00:
+ // ssg
+ warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
+ break;
+ case 0x10:
+ // adpcm
+ warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
+ break;
+ case 0x20:
+ if (l == 8) {
+ // Key on/off
+ for (int i = 0; i < 4; i++) {
+ if ((value >> (4 + i)) & 1)
+ _opr[i]->keyOn();
+ else
+ _opr[i]->keyOff();
+ }
+ } else if (l == 2) {
+ // LFO
+ warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)");
+ } else if (l == 7) {
+ // Timers; Ch 3/6 special mode
+ warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE (NOT SUPPORTED)");
+ } else if (l == 4 || l == 5) {
+ // Timer A
+ warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_A (NOT SUPPORTED)");
+ } else if (l == 6) {
+ // Timer B
+ warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_B (NOT SUPPORTED)");
+ } else if (l == 10 || l == 11) {
+ // DAC
+ warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)");
+ }
+ break;
+
+ case 0x30:
+ // detune, multiple
+ _opr[o]->detune((value >> 4) & 7);
+ _opr[o]->multiple(value & 0x0f);
+ _updateEnvelopes = true;
+ break;
+
+ case 0x40:
+ // total level
+ _opr[o]->totalLevel(value & 0x7f);
+ break;
+
+ case 0x50:
+ // rate scaling, attack rate
+ _opr[o]->attackRate(value & 0x1f);
+ if (_opr[o]->scaleRate(value >> 6))
+ _updateEnvelopes = true;
+ break;
+
+ case 0x60:
+ // first decay rate, amplitude modulation
+ _opr[o]->decayRate(value & 0x1f);
+ if (value & 0x80)
+ warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)");
+
+ break;
+
+ case 0x70:
+ // secondary decay rate
+ _opr[o]->sustainRate(value & 0x1f);
+ break;
+
+ case 0x80:
+ // secondary amplitude, release rate;
+ _opr[o]->sustainLevel(value >> 4);
+ _opr[o]->releaseRate(value & 0x0f);
+ break;
+
+ case 0x90:
+ // ssg
+ warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
+ break;
+
+ case 0xa0:
+ // frequency
+ l -= _regOffset;
+ if (l == 0) {
+ _frqTemp = (_frqTemp & 0xff00) | value;
+ _updateEnvelopes = true;
+ for (int i = 0; i < 4; i++)
+ _opr[i]->frequency(_frqTemp);
+ } else if (l == 4) {
+ _frqTemp = (_frqTemp & 0xff) | (value << 8);
+ } else if (l == 8) {
+ // Ch 3/6 special mode frq
+ warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
+ } else if (l == 12) {
+ // Ch 3/6 special mode frq
+ warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
+ }
+ break;
+
+ case 0xb0:
+ l -= _regOffset;
+ if (l == 0) {
+ // feedback, _algorithm
+ _opr[0]->feedbackLevel((value >> 3) & 7);
+ _opr[1]->feedbackLevel(0);
+ _opr[2]->feedbackLevel(0);
+ _opr[3]->feedbackLevel(0);
+ } else if (l == 4) {
+ // stereo, LFO sensitivity
+ _enableLeft = value & 0x80 ? true : false;
+ _enableRight = value & 0x40 ? true : false;
+ uint8 ams = (value & 0x3F) >> 3;
+ if (ams)
+ warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)");
+ uint8 fms = value & 3;
+ if (fms)
+ warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)");
+ }
+ break;
+
+ default:
+ warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
+ break;
+ }
+}
+
+bool TownsPC98_OpnChannel::control_f0_setPatch(uint8 para) {
+ _instrID = para;
+ uint8 reg = _regOffset + 0x80;
+
+ for (int i = 0; i < 4; i++) {
+ // set release rate for each operator
+ writeReg(reg, 0x0f);
+ reg += 4;
+ }
+
+ const uint8 *tptr = _drv->_patches + ((uint32)_instrID << 5);
+ reg = _regOffset + 0x30;
+
+ // write registers 0x30 to 0x8f
+ for (int i = 0; i < 6; i++) {
+ writeReg(reg, tptr[0]);
+ reg += 4;
+ writeReg(reg, tptr[2]);
+ reg += 4;
+ writeReg(reg, tptr[1]);
+ reg += 4;
+ writeReg(reg, tptr[3]);
+ reg += 4;
+ tptr += 4;
+ }
+
+ reg = _regOffset + 0xB0;
+ _algorithm = tptr[0] & 7;
+ // set feedback and algorithm
+ writeReg(reg, tptr[0]);
+
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f1_presetOutputLevel(uint8 para) {
+ if (_fading)
+ return true;
+
+ _totalLevel = _drv->_opnLvlPresets[para];
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f2_setKeyOffTime(uint8 para) {
+ _keyOffTime = para;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f3_setFreqLSB(uint8 para) {
+ _frqLSB = (int8) para;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f4_setOutputLevel(uint8 para) {
+ if (_fading)
+ return true;
+
+ _totalLevel = para;
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f5_setTempo(uint8 para) {
+ _drv->setTempo(para);
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f6_repeatSection(uint8 para) {
+ _dataPtr--;
+ _dataPtr[0]--;
+
+ if (*_dataPtr) {
+ // repeat section until counter has reached zero
+ _dataPtr = _drv->_trackData + READ_LE_UINT16(_dataPtr + 2);
+ } else {
+ // reset counter, advance to next section
+ _dataPtr[0] = _dataPtr[1];
+ _dataPtr += 4;
+ }
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f7_setupPitchWheel(uint8 para) {
+ _ptchWhlInitDelayLo = _dataPtr[0];
+ _ptchWhlInitDelayHi = para;
+ _ptchWhlModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1);
+ _ptchWhlDuration = _dataPtr[3];
+ _dataPtr += 4;
+ _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF | CHS_RECALCFREQ;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f8_togglePitchWheel(uint8 para) {
+ if (para == 0x10) {
+ if (*_dataPtr++) {
+ _flags = (_flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF;
+ } else {
+ _flags |= CHS_PITCHWHEELOFF;
+ }
+ } else {
+ //uint8 skipChannels = para / 36;
+ //uint8 entry = para % 36;
+ //TownsPC98_OpnDriver::TownsPC98_OpnChannel *t = &chan[skipChannels];
+ ////// NOT IMPLEMENTED
+ //t->unnamedEntries[entry] = *_dataPtr++;
+ }
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fa_writeReg(uint8 para) {
+ writeReg(para, *_dataPtr++);
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fb_incOutLevel(uint8 para) {
+ _dataPtr--;
+ if (_fading)
+ return true;
+
+ uint8 val = (_totalLevel + 3);
+ if (val > 0x7f)
+ val = 0x7f;
+
+ _totalLevel = val;
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fc_decOutLevel(uint8 para) {
+ _dataPtr--;
+ if (_fading)
+ return true;
+
+ int8 val = (int8) (_totalLevel - 3);
+ if (val < 0)
+ val = 0;
+
+ _totalLevel = (uint8) val;
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fd_jump(uint8 para) {
+ uint8 *tmp = _drv->_trackData + READ_LE_UINT16(_dataPtr - 1);
+ _dataPtr = (tmp[1] == 1) ? tmp : ++_dataPtr;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_dummy(uint8 para) {
+ _dataPtr--;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_ff_endOfTrack(uint8 para) {
+ uint16 val = READ_LE_UINT16(--_dataPtr);
+ if (val) {
+ // loop
+ _dataPtr = _drv->_trackData + val;
+ return true;
+ } else {
+ // quit parsing for active channel
+ --_dataPtr;
+ _flags |= CHS_EOT;
+ _drv->_finishedChannelsFlag |= _idFlag;
+ keyOff();
+ return false;
+ }
+}
+
+bool TownsPC98_OpnChannel::control_f0_setPatchSSG(uint8 para) {
+ _instrID = para << 4;
+ para = (para >> 3) & 0x1e;
+ if (para)
+ return control_f4_setAlgorithm(para | 0x40);
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f1_setTotalLevel(uint8 para) {
+ if (!_fading)
+ _totalLevel = para;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f4_setAlgorithm(uint8 para) {
+ _algorithm = para;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_f9_unkSSG(uint8 para) {
+ _dataPtr += 5;
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fb_incOutLevelSSG(uint8 para) {
+ _dataPtr--;
+ if (_fading)
+ return true;
+
+ _totalLevel--;
+ if ((int8)_totalLevel < 0);
+ _totalLevel = 0;
+
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_fc_decOutLevelSSG(uint8 para) {
+ _dataPtr--;
+ if (_fading)
+ return true;
+
+ if(_totalLevel + 1 < 0x10)
+ _totalLevel++;
+
+ return true;
+}
+
+bool TownsPC98_OpnChannel::control_ff_endOfTrackSSG(uint8 para) {
+ uint16 val = READ_LE_UINT16(--_dataPtr);
+ if (val) {
+ // loop
+ _dataPtr = _drv->_trackData + val;
+ return true;
+ } else {
+ // quit parsing for active channel
+ --_dataPtr;
+ _flags |= CHS_EOT;
+ //_finishedChannelsFlag |= _idFlag;
+ keyOff();
+ return false;
+ }
+}
+
+TownsPC98_OpnChannelSSG::TownsPC98_OpnChannelSSG(TownsPC98_OpnDriver *driver, uint8 regOffs,
+ uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
+ TownsPC98_OpnChannel(driver, regOffs, flgs, num, key, prt, id) {
+}
+
+void TownsPC98_OpnChannelSSG::init() {
+ _algorithm = 0x80;
+
+ _opr = new TownsPC98_OpnOperator*[4];
+ for (int i = 0; i < 4; i++)
+ _opr[i] = new TownsPC98_OpnOperator(_drv->_baserate, _drv->_oprRates, _drv->_oprRateshift,
+ _drv->_oprAttackDecay, _drv->_oprFrq, _drv->_oprSinTbl, _drv->_oprLevelOut, _drv->_oprDetune);
+
+ #define Control(x) &TownsPC98_OpnChannelSSG::control_##x
+ static const ControlEventFunc ctrlEventsSSG[] = {
+ Control(f0_setPatchSSG),
+ Control(f1_setTotalLevel),
+ Control(f2_setKeyOffTime),
+ Control(f3_setFreqLSB),
+ Control(f4_setOutputLevel),
+ Control(f5_setTempo),
+ Control(f6_repeatSection),
+ Control(f7_setupPitchWheel),
+ Control(f8_togglePitchWheel),
+ Control(f9_unkSSG),
+ Control(fa_writeReg),
+ Control(fb_incOutLevelSSG),
+ Control(fc_decOutLevelSSG),
+ Control(fd_jump),
+ Control(dummy),
+ Control(ff_endOfTrackSSG)
+ };
+ #undef Control
+
+ controlEvents = ctrlEventsSSG;
+}
+
+void TownsPC98_OpnChannelSSG::processEvents() {
+ if (_flags & CHS_EOT)
+ return;
+
+ int _ssgUnk = (_flags & CHS_SSG) ? -1 : 0;
+
+ if (_protect == false && _ticksLeft == _keyOffTime)
+ keyOff();
+
+ if (--_ticksLeft)
+ return;
+
+ if (_protect == false)
+ keyOff();
+
+ uint8 cmd = 0;
+ bool loop = true;
+
+ while (loop) {
+ cmd = *_dataPtr++;
+ if (cmd < 0xf0)
+ loop = false;
+ else if (!processControlEvent(cmd))
+ return;
+ }
+
+ uint8 para = *_dataPtr++;
+
+ if (cmd == 0x80) {
+ keyOff();
+ _protect = false;
+ } else {
+ keyOn();
+
+ if (_protect == false || cmd != _frqBlockMSB)
+ _flags |= CHS_RECALCFREQ;
+
+ _protect = (para & 0x80) ? true : false;
+ _frqBlockMSB = cmd;
+ }
+
+ _ticksLeft = para & 0x7f;
+
+ if (!(_flags & CHS_SSG)) {
+
+ }
+}
+
+void TownsPC98_OpnChannelSSG::processFrequency() {
+ if (_flags & CHS_RECALCFREQ) {
+ uint8 block = (_frqBlockMSB & 0x70) >> 1;
+ uint16 bfreq = ((const uint16*)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f];
+ frequency = (bfreq + _frqLSB) | (block << 8);
+
+ writeReg(_regOffset + 0xa4, (frequency >> 8));
+ writeReg(_regOffset + 0xa0, (frequency & 0xff));
+
+ _ptchWhlCurDelay = _ptchWhlInitDelayHi;
+ if (_flags & CHS_KEYOFF) {
+ _ptchWhlModCurVal = _ptchWhlModInitVal;
+ _ptchWhlCurDelay += _ptchWhlInitDelayLo;
+ }
+
+ _ptchWhlDurLeft = (_ptchWhlDuration >> 1);
+ _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ);
+ }
+
+ if (!(_flags & CHS_PITCHWHEELOFF)) {
+ if (--_ptchWhlCurDelay)
+ return;
+ _ptchWhlCurDelay = _ptchWhlInitDelayHi;
+ frequency += _ptchWhlModCurVal;
+
+ writeReg(_regOffset + 0xa4, (frequency >> 8));
+ writeReg(_regOffset + 0xa0, (frequency & 0xff));
+
+ if(!--_ptchWhlDurLeft) {
+ _ptchWhlDurLeft = _ptchWhlDuration;
+ _ptchWhlModCurVal = -_ptchWhlModCurVal;
+ }
+ }
+}
+
+void TownsPC98_OpnChannelSSG::keyOff() {
+ // all operators off
+ uint8 value = _keyNum & 0x0f;
+ uint8 regAdress = 0x28;
+ writeReg(regAdress, value);
+ _flags |= CHS_KEYOFF;
+}
+
+void TownsPC98_OpnChannelSSG::keyOn() {
+ // all operators on
+ uint8 value = _keyNum | 0xf0;
+ uint8 regAdress = 0x28;
+ writeReg(regAdress, value);
+}
+
TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) :
- _mixer(mixer), _trackData(0), _playing(false), _fading(false), _channels(0),
- _operators(0), _looping(0), _twnCarrier(_drvTables + 76), _twnFreqTable(_drvTables + 84),
- _twnFxCmdLen(_drvTables + 36), _twnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) ,
+ _mixer(mixer), _trackData(0), _playing(false), _channels(0), _ssgChannels(0),
+ _looping(0), _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 84),
+ _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == OD_TOWNS ? 52 : 220)) ,
_oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0),
_oprDetune(0), _cbCounter(4), _tickCounter(0), _updateChannelsFlag(type == OD_TYPE26 ? 0x07 : 0x3F),
- _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0),
+ _finishedChannelsFlag(0), _samplesTillCallback(0), _samplesTillCallbackRemainder(0), _ready(false),
_numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false),
_numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) {
setTempo(84);
@@ -1502,18 +2351,18 @@ TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) :
TownsPC98_OpnDriver::~TownsPC98_OpnDriver() {
_mixer->stopHandle(_soundHandle);
- if (_operators) {
- for (int i = 0; i < (_numChan << 2); i++)
- delete _operators[i];
- delete [] _operators;
- }
-
if (_channels) {
for (int i = 0; i < _numChan; i++)
delete _channels[i];
delete [] _channels;
}
+ if (_ssgChannels) {
+ for (int i = 0; i < _numSSG; i++)
+ delete _ssgChannels[i];
+ delete [] _ssgChannels;
+ }
+
delete [] _oprRates;
delete [] _oprRateshift;
delete [] _oprFrq;
@@ -1524,21 +2373,12 @@ TownsPC98_OpnDriver::~TownsPC98_OpnDriver() {
}
bool TownsPC98_OpnDriver::init() {
- generateTables();
-
- if (_operators) {
- for (int i = 0; i < (_numChan << 2); i++) {
- if (_operators[i]) {
- delete _operators[i];
- }
- }
- delete [] _operators;
+ if (_ready) {
+ reset();
+ return true;
}
- _operators = new TownsPC98_OpnOperator*[(_numChan << 2)];
- for (int i = 0; i < (_numChan << 2); i++)
- _operators[i] = new TownsPC98_OpnOperator(_baserate, _oprRates,
- _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune);
+ generateTables();
if (_channels) {
for (int i = 0; i < _numChan; i++) {
@@ -1547,29 +2387,35 @@ bool TownsPC98_OpnDriver::init() {
}
delete [] _channels;
}
- _channels = new TwnChannel*[_numChan];
+ _channels = new TownsPC98_OpnChannel*[_numChan];
for (int i = 0; i < _numChan; i++) {
- _channels[i] = new TwnChannel;
- for (int ii = 0; ii < 4; ii++) {
- _channels[i]->opr[ii] = _operators[(i << 2) + ii];
- _channels[i]->updateEnvelopes = false;
- }
+ int ii = i * 6;
+ _channels[i] = new TownsPC98_OpnChannel(this, _drvTables[ii], _drvTables[ii + 1],
+ _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
+ _channels[i]->init();
}
- for (int i = 0; i < _numChan; i++) {
- int ix = i * 6;
- memset(_channels[i], 0, sizeof(TwnChannel));
- _channels[i]->regOffset = _drvTables[ix];
- _channels[i]->flags = _drvTables[ix + 1];
- _channels[i]->chanNum = _drvTables[ix + 2];
- _channels[i]->keyNum = _drvTables[ix + 3];
- _channels[i]->part = _drvTables[ix + 4];
- _channels[i]->idFlag = _drvTables[ix + 5];
+ if (_ssgChannels) {
+ for (int i = 0; i < _numSSG; i++) {
+ if (_ssgChannels[i])
+ delete _ssgChannels[i];
+ }
+ delete [] _ssgChannels;
+ }
+ if (_numSSG) {
+ _ssgChannels = new TownsPC98_OpnChannelSSG*[_numSSG];
+ for (int i = 0; i < _numSSG; i++) {
+ int ii = i * 6;
+ _ssgChannels[i] = new TownsPC98_OpnChannelSSG(this, _drvTables[ii], _drvTables[ii + 1],
+ _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
+ _ssgChannels[i]->init();
+ }
}
_mixer->playInputStream(Audio::Mixer::kMusicSoundType,
&_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true);
+ _ready = true;
return true;
}
@@ -1604,82 +2450,31 @@ int inline TownsPC98_OpnDriver::readBuffer(int16 *buffer, const int numSamples)
return numSamples;
}
-void TownsPC98_OpnDriver::loadData(uint8 * data, bool loadPaused) {
+void TownsPC98_OpnDriver::loadData(uint8 *data, bool loadPaused) {
+ if (!_ready) {
+ warning("TownsPC98_OpnDriver: Driver must be initialized before loading data");
+ return;
+ }
+
+ if (!data) {
+ warning("TownsPC98_OpnDriver: Invalid music file data");
+ return;
+ }
lock();
_trackData = data;
reset();
-
- for (uint8 i = 0; i < _numChan; i++) {
- uint8 tmp1 = _channels[i]->regOffset;
- uint8 tmp2 = _channels[i]->flags;
- uint8 tmp3 = _channels[i]->chanNum;
- uint8 tmp4 = _channels[i]->keyNum;
- uint8 tmp5 = _channels[i]->part;
- uint8 tmp6 = _channels[i]->idFlag;
- memset(_channels[i], 0, sizeof(TwnChannel));
- _channels[i]->regOffset = tmp1;
- _channels[i]->flags = tmp2;
- _channels[i]->chanNum = tmp3;
- _channels[i]->keyNum = tmp4;
- _channels[i]->part = tmp5;
- _channels[i]->idFlag = tmp6;
- _channels[i]->enableLeft = _channels[i]->enableRight = true;
- for (int ii = 0; ii < 4; ii++)
- _channels[i]->opr[ii] = _operators[(i << 2) + ii];
- }
-
+
uint8 *src_a = data;
- uint8 bl = 0;
for (uint8 i = 0; i < _numChan; i++) {
- _channels[i]->flags = (_channels[i]->flags & ~CHS_EOT) | CHS_ALL_BUT_EOT;
- _channels[i]->ticksLeft = 1;
- _channels[i]->dataPtr = data + READ_LE_UINT16(src_a);
+ _channels[i]->loadData(data + READ_LE_UINT16(src_a));
src_a += 2;
- _channels[i]->totalLevel = 0x7F;
- if (bl > 2)
- bl -= 3;
- _channels[i]->regOffset = bl++;
-
- uint8 * src_b = _channels[i]->dataPtr;
- int loop = 1;
- uint8 cmd = 0;
- while (loop) {
- if (loop == 1) {
- cmd = *src_b++;
- if (cmd < 0xf0) {
- src_b++;
- loop = 1;
- } else {
- if (cmd == 0xff) {
- loop = *src_b ? 2 : 0;
- if (READ_LE_UINT16(src_b))
- _looping |= _channels[i]->idFlag;
- } else if (cmd == 0xf6) {
- loop = 3;
- } else {
- loop = 2;
- }
- }
- } else if (loop == 2) {
- src_b += _twnFxCmdLen[cmd - 240];
- loop = 1;
- } else if (loop == 3) {
- src_b[0] = src_b[1];
- src_b += 4;
- loop = 1;
- }
- }
}
for (int i = 0; i < _numSSG; i++) {
- // TODO
- //_channels[i]->flags = (_channels[i]->flags & ~CHS_EOT) | CHS_ALL_BUT_EOT;
- //_channels[i]->ticksLeft = 1;
- //_channels[i]->dataPtr = data + READ_LE_UINT16(src_a);
- //uint8 *tmp = data + READ_LE_UINT16(src_a);
+ _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a));
src_a += 2;
}
@@ -1698,8 +2493,10 @@ void TownsPC98_OpnDriver::loadData(uint8 * data, bool loadPaused) {
}
void TownsPC98_OpnDriver::reset() {
- for (int i = 0; i < (_numChan << 2); i++)
- _operators[i]->reset();
+ for (int i = 0; i < (_numChan); i++)
+ _channels[i]->reset();
+ for (int i = 0; i < (_numSSG); i++)
+ _ssgChannels[i]->reset();
_playing = false;
_looping = 0;
@@ -1710,21 +2507,21 @@ void TownsPC98_OpnDriver::fadeOut() {
if (!_playing)
return;
- _fading = true;
+ for (int j = 0; j < _numChan; j++)
+ _channels[j]->_fading = true;
+ for (int j = 0; j < _numSSG; j++)
+ _ssgChannels[j]->_fading = true;
- for (int i = 0; i < 20; i++) {
-
+ for (int i = 0; i < 20; i++) {
lock();
uint32 dTime = _tickCounter + 2;
for (int j = 0; j < _numChan; j++) {
- if (_updateChannelsFlag & _channels[j]->idFlag) {
- uint8 tmp = _channels[j]->totalLevel + 3;
- if (tmp > 0x7f)
- tmp = 0x7f;
- _channels[j]->totalLevel = tmp;
- setOutputLevel(_channels[j]);
- }
+ if (_updateChannelsFlag & _channels[j]->_idFlag)
+ _channels[j]->fadeStep();
}
+ for (int j = 0; j < _numSSG; j++)
+ _ssgChannels[j]->fadeStep();
+
unlock();
while (_playing) {
@@ -1733,7 +2530,10 @@ void TownsPC98_OpnDriver::fadeOut() {
}
}
- _fading = false;
+ for (int j = 0; j < _numChan; j++)
+ _channels[j]->_fading = false;
+ for (int j = 0; j < _numSSG; j++)
+ _ssgChannels[j]->_fading = false;
reset();
}
@@ -1746,12 +2546,21 @@ void TownsPC98_OpnDriver::callback() {
_tickCounter++;
lock();
+
for (int i = 0; i < _numChan; i++) {
- if (_updateChannelsFlag & _channels[i]->idFlag) {
- processEvents(_channels[i]);
- processFrequency(_channels[i]);
+ if (_updateChannelsFlag & _channels[i]->_idFlag) {
+ _channels[i]->processEvents();
+ _channels[i]->processFrequency();
}
}
+
+ if (_numSSG) {
+ for (int i = 0; i < _numSSG; i++) {
+ _ssgChannels[i]->processEvents();
+ _ssgChannels[i]->processFrequency();
+ }
+ }
+
unlock();
if (_finishedChannelsFlag == _updateChannelsFlag)
@@ -1763,96 +2572,25 @@ void TownsPC98_OpnDriver::nextTick(int16 *buffer, uint32 bufferSize) {
return;
for (int i = 0; i < _numChan ; i++) {
- if (_channels[i]->updateEnvelopes) {
- _channels[i]->updateEnvelopes = false;
- for (int ii = 0; ii < 4 ; ii++)
- _channels[i]->opr[ii]->updatePhaseIncrement();
+ if (_channels[i]->_updateEnvelopes) {
+ _channels[i]->_updateEnvelopes = false;
+ _channels[i]->updateEnv();
}
-
- int phbuf1, phbuf2, output;
- int *feed = _channels[i]->feedbuf;
- int *del = &feed[2];
- for (uint32 ii = 0; ii < bufferSize ; ii++) {
- phbuf1 = phbuf2 = output = 0;
-
- switch (_channels[i]->algorithm) {
- case 0:
- _channels[i]->opr[0]->generateOutput(0, feed, phbuf1);
- _channels[i]->opr[2]->generateOutput(*del, 0, phbuf2);
- *del = 0;
- _channels[i]->opr[1]->generateOutput(phbuf1, 0, *del);
- _channels[i]->opr[3]->generateOutput(phbuf2, 0, output);
- break;
- case 1:
- _channels[i]->opr[0]->generateOutput(0, feed, phbuf1);
- _channels[i]->opr[2]->generateOutput(*del, 0, phbuf2);
- _channels[i]->opr[1]->generateOutput(0, 0, phbuf1);
- _channels[i]->opr[3]->generateOutput(phbuf2, 0, output);
- *del = phbuf1;
- break;
- case 2:
- _channels[i]->opr[0]->generateOutput(0, feed, phbuf2);
- _channels[i]->opr[2]->generateOutput(*del, 0, phbuf2);
- _channels[i]->opr[1]->generateOutput(0, 0, phbuf1);
- _channels[i]->opr[3]->generateOutput(phbuf2, 0, output);
- *del = phbuf1;
- break;
- case 3:
- _channels[i]->opr[0]->generateOutput(0, feed, phbuf2);
- _channels[i]->opr[2]->generateOutput(0, 0, *del);
- _channels[i]->opr[1]->generateOutput(phbuf2, 0, phbuf1);
- _channels[i]->opr[3]->generateOutput(*del, 0, output);
- *del = phbuf1;
- break;
- case 4:
- _channels[i]->opr[0]->generateOutput(0, feed, phbuf1);
- _channels[i]->opr[2]->generateOutput(0, 0, phbuf2);
- _channels[i]->opr[1]->generateOutput(phbuf1, 0, output);
- _channels[i]->opr[3]->generateOutput(phbuf2, 0, output);
- *del = 0;
- break;
- case 5:
- *del = feed[1];
- _channels[i]->opr[0]->generateOutput(-1, feed, phbuf1);
- _channels[i]->opr[2]->generateOutput(*del, 0, output);
- _channels[i]->opr[1]->generateOutput(*del, 0, output);
- _channels[i]->opr[3]->generateOutput(*del, 0, output);
- break;
- case 6:
- _channels[i]->opr[0]->generateOutput(0, feed, phbuf1);
- _channels[i]->opr[2]->generateOutput(0, 0, output);
- _channels[i]->opr[1]->generateOutput(phbuf1, 0, output);
- _channels[i]->opr[3]->generateOutput(0, 0, output);
- *del = 0;
- break;
- case 7:
- _channels[i]->opr[0]->generateOutput(0, feed, output);
- _channels[i]->opr[2]->generateOutput(0, 0, output);
- _channels[i]->opr[1]->generateOutput(0, 0, output);
- _channels[i]->opr[3]->generateOutput(0, 0, output);
- *del = 0;
- break;
- };
-
- if (_channels[i]->enableLeft) {
- int l = output + buffer[ii * 2];
- if (l > 32767)
- l = 32767;
- if (l < -32767)
- l = -32767;
- buffer[ii * 2] = (int16) l;
- }
+ for (uint32 ii = 0; ii < bufferSize ; ii++)
+ _channels[i]->generateOutput(buffer[ii * 2],
+ buffer[ii * 2 + 1], &_channels[i]->_feedbuf[2], _channels[i]->_feedbuf);
+ }
- if (_channels[i]->enableRight) {
- int r = output + buffer[ii * 2 + 1];
- if (r > 32767)
- r = 32767;
- if (r < -32767)
- r = -32767;
- buffer[ii * 2 + 1] = (int16) r;
- }
+ for (int i = 0; i < _numSSG ; i++) {
+ if (_ssgChannels[i]->_updateEnvelopes) {
+ _ssgChannels[i]->_updateEnvelopes = false;
+ _ssgChannels[i]->updateEnv();
}
+
+ for (uint32 ii = 0; ii < bufferSize ; ii++)
+ _ssgChannels[i]->generateOutput(buffer[ii * 2],
+ buffer[ii * 2 + 1], &_ssgChannels[i]->_feedbuf[2], _ssgChannels[i]->_feedbuf);
}
}
@@ -1860,7 +2598,7 @@ void TownsPC98_OpnDriver::generateTables() {
delete [] _oprRates;
_oprRates = new uint8[128];
memset(_oprRates, 0x90, 32);
- uint8 * dst = (uint8*) _oprRates + 32;
+ uint8 *dst = (uint8*) _oprRates + 32;
for (int i = 0; i < 48; i += 4)
WRITE_BE_UINT32(dst + i, 0x00081018);
dst += 48;
@@ -1913,7 +2651,7 @@ void TownsPC98_OpnDriver::generateTables() {
}
}
- uint8 * dtt = new uint8[128];
+ uint8 *dtt = new uint8[128];
memset(dtt, 0, 36);
memset(dtt + 36, 1, 8);
memcpy(dtt + 44, _drvTables + 144, 84);
@@ -1928,448 +2666,12 @@ void TownsPC98_OpnDriver::generateTables() {
delete [] dtt;
}
-void TownsPC98_OpnDriver::processEvents(TwnChannel *chan) {
- if (chan->flags & CHS_EOT)
- return;
-
- if (chan->protect == false && chan->ticksLeft == chan->keyOffTime)
- keyOff(chan);
-
- if (--chan->ticksLeft)
- return;
-
- if (chan->protect == false)
- keyOff(chan);
-
- uint8 cmd = 0;
- bool loop = true;
-
- while (loop) {
- cmd = *chan->dataPtr++;
- if (cmd < 0xf0)
- loop = false;
- else if (!processControlEvent(chan, cmd))
- return;
- }
-
- uint8 para = *chan->dataPtr++;
-
- if (cmd == 0x80) {
- keyOff(chan);
- chan->protect = false;
- } else {
- keyOn(chan);
-
- if (chan->protect == false || cmd != chan->frqBlockMSB)
- chan->flags |= CHS_RECALCFREQ;
-
- chan->protect = (para & 0x80) ? true : false;
- chan->frqBlockMSB = cmd;
- }
-
- chan->ticksLeft = para & 0x7f;
-}
-
-void TownsPC98_OpnDriver::processFrequency(TwnChannel *chan) {
- if (chan->flags & CHS_RECALCFREQ) {
- uint8 block = (chan->frqBlockMSB & 0x70) >> 1;
- uint16 bfreq = ((const uint16*)_twnFreqTable)[chan->frqBlockMSB & 0x0f];
- chan->frequency = (bfreq + chan->frqLSB) | (block << 8);
-
- writeReg(chan, (chan->regOffset + 0xa4), (chan->frequency >> 8));
- writeReg(chan, (chan->regOffset + 0xa0), (chan->frequency & 0xff));
-
- chan->ptchWhlCurDelay = chan->ptchWhlInitDelayHi;
- if (chan->flags & CHS_KEYOFF) {
- chan->ptchWhlModCurVal = chan->ptchWhlModInitVal;
- chan->ptchWhlCurDelay += chan->ptchWhlInitDelayLo;
- }
-
- chan->ptchWhlDurLeft = (chan->ptchWhlDuration >> 1);
- chan->flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ);
- }
-
- if (!(chan->flags & CHS_PITCHWHEELOFF)) {
- if (--chan->ptchWhlCurDelay)
- return;
- chan->ptchWhlCurDelay = chan->ptchWhlInitDelayHi;
- chan->frequency += chan->ptchWhlModCurVal;
-
- writeReg(chan, (chan->regOffset + 0xa4), (chan->frequency >> 8));
- writeReg(chan, (chan->regOffset + 0xa0), (chan->frequency & 0xff));
-
- if(!--chan->ptchWhlDurLeft) {
- chan->ptchWhlDurLeft = chan->ptchWhlDuration;
- chan->ptchWhlModCurVal = -chan->ptchWhlModCurVal;
- }
- }
-}
-
-bool TownsPC98_OpnDriver::processControlEvent(TwnChannel *chan, uint8 cmd) {
- #define Control(x) &TownsPC98_OpnDriver::control_##x
- static const ControlEventFunc twnFxCommands[] = {
- Control(f0_setPatch),
- Control(f1_presetOutputLevel),
- Control(f2_setKeyOffTime),
- Control(f3_setFreqLSB),
- Control(f4_setOutputLevel),
- Control(f5_setTempo),
- Control(f6_repeatSection),
- Control(f7_setupPitchWheel),
- Control(f8_togglePitchWheel),
- Control(f9_unk),
- Control(fa_writeReg),
- Control(fb_incOutLevel),
- Control(fc_decOutLevel),
- Control(fd_jump),
- Control(fe_unk),
- Control(ff_endOfTrack)
- };
- #undef Control
-
- uint8 para = *chan->dataPtr++;
- return (this->*twnFxCommands[cmd & 0x0f])(chan, para);
-}
-
-void TownsPC98_OpnDriver::setOutputLevel(TwnChannel *chan) {
- uint8 outopr = _twnCarrier[chan->algorithm];
- uint8 reg = 0x40 + chan->regOffset;
-
- for (int i = 0; i < 4; i++) {
- if (outopr & 1)
- writeReg(chan, reg, chan->totalLevel);
- outopr >>= 1;
- reg += 4;
- }
-}
-
void TownsPC98_OpnDriver::setTempo(uint8 tempo) {
_tempo = tempo;
_samplesPerCallback = getRate() / _tempo;
_samplesPerCallbackRemainder = getRate() % _tempo;
}
-bool TownsPC98_OpnDriver::control_f0_setPatch(TwnChannel *chan, uint8 para) {
- chan->instrID = para;
- uint8 reg = chan->regOffset + 0x80;
-
- for (int i = 0; i < 4; i++) {
- // set release rate for each operator
- writeReg(chan, reg, 0x0f);
- reg += 4;
- }
-
- const uint8 *tptr = _patches + ((uint32)chan->instrID << 5);
- reg = chan->regOffset + 0x30;
-
- // write registers 0x30 to 0x8f
- for (int i = 0; i < 6; i++) {
- writeReg(chan, reg, tptr[0]);
- reg += 4;
- writeReg(chan, reg, tptr[2]);
- reg += 4;
- writeReg(chan, reg, tptr[1]);
- reg += 4;
- writeReg(chan, reg, tptr[3]);
- reg += 4;
- tptr += 4;
- }
-
- reg = chan->regOffset + 0xB0;
- chan->algorithm = tptr[0] & 7;
- // set feedback and algorithm
- writeReg(chan, reg, tptr[0]);
-
- setOutputLevel(chan);
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_f1_presetOutputLevel(TwnChannel *chan, uint8 para) {
- if (_fading)
- return true;
-
- chan->totalLevel = _twnLvlPresets[para];
- setOutputLevel(chan);
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_f2_setKeyOffTime(TwnChannel *chan, uint8 para) {
- chan->keyOffTime = para;
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_f3_setFreqLSB(TwnChannel *chan, uint8 para) {
- chan->frqLSB = (int8) para;
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_f4_setOutputLevel(TwnChannel *chan, uint8 para) {
- if (_fading)
- return true;
-
- chan->totalLevel = para;
- setOutputLevel(chan);
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_f5_setTempo(TwnChannel *chan, uint8 para) {
- setTempo(para);
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_f6_repeatSection(TwnChannel *chan, uint8 para) {
- chan->dataPtr--;
- chan->dataPtr[0]--;
-
- if (*chan->dataPtr) {
- // repeat section until counter has reached zero
- chan->dataPtr = _trackData + READ_LE_UINT16(chan->dataPtr + 2);
- } else {
- // reset counter, advance to next section
- chan->dataPtr[0] = chan->dataPtr[1];
- chan->dataPtr += 4;
- }
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_f7_setupPitchWheel(TwnChannel *chan, uint8 para) {
- chan->ptchWhlInitDelayLo = chan->dataPtr[0];
- chan->ptchWhlInitDelayHi = para;
- chan->ptchWhlModInitVal = (int16) READ_LE_UINT16(chan->dataPtr + 1);
- chan->ptchWhlDuration = chan->dataPtr[3];
- chan->dataPtr += 4;
- chan->flags = (chan->flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF | CHS_RECALCFREQ;
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_f8_togglePitchWheel(TwnChannel *chan, uint8 para) {
- if (para == 0x10) {
- if (*chan->dataPtr++) {
- chan->flags = (chan->flags & ~CHS_PITCHWHEELOFF) | CHS_KEYOFF;
- } else {
- chan->flags |= CHS_PITCHWHEELOFF;
- }
- } else {
- //uint8 skipChannels = para / 36;
- //uint8 entry = para % 36;
- //TownsPC98_OpnDriver::TwnChannel *t = &chan[skipChannels];
- ////// NOT IMPLEMENTED
- //t->unnamedEntries[entry] = *chan->dataPtr++;
- }
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_f9_unk(TwnChannel *chan, uint8 para) {
- //chan->dataPtr += 5;
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_fa_writeReg(TwnChannel *chan, uint8 para) {
- writeReg(chan, para, *chan->dataPtr++);
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_fb_incOutLevel(TwnChannel *chan, uint8 para) {
- chan->dataPtr--;
- if (_fading)
- return true;
-
- uint8 val = (chan->totalLevel + 3);
- if (val > 0x7f)
- val = 0x7f;
-
- chan->totalLevel = val;
- setOutputLevel(chan);
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_fc_decOutLevel(TwnChannel *chan, uint8 para) {
- chan->dataPtr--;
- if (_fading)
- return true;
-
- int8 val = (int8) (chan->totalLevel - 3);
- if (val < 0)
- val = 0;
-
- chan->totalLevel = (uint8) val;
- setOutputLevel(chan);
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_fd_jump(TwnChannel *chan, uint8 para) {
- uint8 *tmp = _trackData + READ_LE_UINT16(chan->dataPtr - 1);
- chan->dataPtr = (tmp[1] == 1) ? tmp : ++chan->dataPtr;
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_fe_unk(TwnChannel *chan, uint8 para) {
- chan->dataPtr--;
- return true;
-}
-
-bool TownsPC98_OpnDriver::control_ff_endOfTrack(TwnChannel *chan, uint8 para) {
- uint16 val = READ_LE_UINT16(--chan->dataPtr);
- if (val) {
- // loop
- chan->dataPtr = _trackData + val;
- return true;
- } else {
- // quit parsing for active channel
- --chan->dataPtr;
- chan->flags |= CHS_EOT;
- _finishedChannelsFlag |= chan->idFlag;
- keyOff(chan);
- return false;
- }
-}
-
-void TownsPC98_OpnDriver::keyOff(TwnChannel *chan) {
- // all operators off
- uint8 value = chan->keyNum & 0x0f;
- uint8 regAdress = 0x28;
- writeReg(chan, regAdress, value);
- chan->flags |= CHS_KEYOFF;
-}
-
-void TownsPC98_OpnDriver::keyOn(TwnChannel *chan) {
- // all operators on
- uint8 value = chan->keyNum | 0xf0;
- uint8 regAdress = 0x28;
- writeReg(chan, regAdress, value);
-}
-
-void TownsPC98_OpnDriver::writeReg(TwnChannel *chan, uint8 regAdress, uint8 value) {
- uint8 h = regAdress & 0xf0;
- uint8 l = (regAdress & 0x0f);
- static const uint8 opr[] = { 0, 2, 1, 3 };
- uint8 o = opr[(l - chan->regOffset) >> 2];
-
- switch (h) {
- case 0x00:
- // ssg
- warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
- break;
- case 0x10:
- // adpcm
- warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
- break;
- case 0x20:
- if (l == 8) {
- // Key on/off
- for (int i = 0; i < 4; i++) {
- if ((value >> (4 + i)) & 1)
- chan->opr[i]->keyOn();
- else
- chan->opr[i]->keyOff();
- }
- } else if (l == 2) {
- // LFO
- warning("TownsPC98_OpnDriver: TRYING TO USE LFO (NOT SUPPORTED)");
- } else if (l == 7) {
- // Timers; Ch 3/6 special mode
- warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE (NOT SUPPORTED)");
- } else if (l == 4 || l == 5) {
- // Timer A
- warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_A (NOT SUPPORTED)");
- } else if (l == 6) {
- // Timer B
- warning("TownsPC98_OpnDriver: TRYING TO USE TIMER_B (NOT SUPPORTED)");
- } else if (l == 10 || l == 11) {
- // DAC
- warning("TownsPC98_OpnDriver: TRYING TO USE DAC (NOT SUPPORTED)");
- }
- break;
-
- case 0x30:
- // detune, multiple
- chan->opr[o]->detune((value >> 4) & 7);
- chan->opr[o]->multiple(value & 0x0f);
- chan->updateEnvelopes = true;
- break;
-
- case 0x40:
- // total level
- chan->opr[o]->totalLevel(value & 0x7f);
- break;
-
- case 0x50:
- // rate scaling, attack rate
- chan->opr[o]->attackRate(value & 0x1f);
- if (chan->opr[o]->scaleRate(value >> 6))
- chan->updateEnvelopes = true;
- break;
-
- case 0x60:
- // first decay rate, amplitude modulation
- chan->opr[o]->decayRate(value & 0x1f);
- if (value & 0x80)
- warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION (NOT SUPPORTED)");
-
- break;
-
- case 0x70:
- // secondary decay rate
- chan->opr[o]->sustainRate(value & 0x1f);
- break;
-
- case 0x80:
- // secondary amplitude, release rate;
- chan->opr[o]->sustainLevel(value >> 4);
- chan->opr[o]->releaseRate(value & 0x0f);
- break;
-
- case 0x90:
- // ssg
- warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
- break;
-
- case 0xa0:
- // frequency
- l -= chan->regOffset;
- if (l == 0) {
- chan->frqTemp = (chan->frqTemp & 0xff00) | value;
- chan->updateEnvelopes = true;
- for (int i = 0; i < 4; i++)
- chan->opr[i]->frequency(chan->frqTemp);
- } else if (l == 4) {
- chan->frqTemp = (chan->frqTemp & 0xff) | (value << 8);
- } else if (l == 8) {
- // Ch 3/6 special mode frq
- warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
- } else if (l == 12) {
- // Ch 3/6 special mode frq
- warning("TownsPC98_OpnDriver: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
- }
- break;
-
- case 0xb0:
- l -= chan->regOffset;
- if (l == 0) {
- // feedback, algorithm
- chan->opr[0]->feedbackLevel((value >> 3) & 7);
- chan->opr[1]->feedbackLevel(0);
- chan->opr[2]->feedbackLevel(0);
- chan->opr[3]->feedbackLevel(0);
- } else if (l == 4) {
- // stereo, LFO sensitivity
- chan->enableLeft = value & 0x80 ? true : false;
- chan->enableRight = value & 0x40 ? true : false;
- uint8 ams = (value & 0x3F) >> 3;
- if (ams)
- warning("TownsPC98_OpnDriver: TRYING TO USE AMP MODULATION SENSITIVITY (NOT SUPPORTED)");
- uint8 fms = value & 3;
- if (fms)
- warning("TownsPC98_OpnDriver: TRYING TO USE FREQ MODULATION SENSITIVITY (NOT SUPPORTED)");
- }
- break;
-
- default:
- warning("TownsPC98_OpnDriver: UNKNOWN ADDRESS %d", regAdress);
- break;
- }
-}
-
const uint8 TownsPC98_OpnDriver::_drvTables[] = {
// channel presets
0x00, 0x80, 0x00, 0x00, 0x00, 0x01,
@@ -2474,7 +2776,7 @@ void SoundTowns::playTrack(uint8 track) {
return;
track -= 2;
- const int32 * const tTable = (const int32 * const) cdaData();
+ const int32 *const tTable = (const int32 *const) cdaData();
int tTableIndex = 3 * track;
int trackNum = (int) READ_LE_UINT32(&tTable[tTableIndex + 2]);
@@ -2545,12 +2847,12 @@ void SoundTowns::playSoundEffect(uint8 track) {
}
}
- uint8 * fileBody = _sfxFileData + 0x01b8;
+ uint8 *fileBody = _sfxFileData + 0x01b8;
int32 offset = (int32)READ_LE_UINT32(_sfxFileData + (track - 0x0b) * 4);
if (offset == -1)
return;
- uint32 * sfxHeader = (uint32*)(fileBody + offset);
+ uint32 *sfxHeader = (uint32*)(fileBody + offset);
uint32 sfxHeaderID = READ_LE_UINT32(sfxHeader);
uint32 sfxHeaderInBufferSize = READ_LE_UINT32(&sfxHeader[1]);
@@ -2570,7 +2872,7 @@ void SoundTowns::playSoundEffect(uint8 track) {
} else if (sfxHeaderID == 1) {
Screen::decodeFrame4(sfxBody, sfxPlaybackBuffer, playbackBufferSize);
} else if (_sfxWDTable) {
- uint8 * tgt = sfxPlaybackBuffer;
+ uint8 *tgt = sfxPlaybackBuffer;
uint32 sfx_BtTable_Offset = 0;
uint32 sfx_WdTable_Offset = 0;
uint32 sfx_WdTable_Number = 5;
@@ -2635,7 +2937,7 @@ uint32 SoundTowns::getBaseTempo(void) {
}
bool SoundTowns::loadInstruments() {
- uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0);
+ uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0);
if (!twm)
return false;
_driver->queue()->loadDataToCurrentPosition(twm, 0x8BF0);
@@ -2650,7 +2952,7 @@ bool SoundTowns::loadInstruments() {
}
void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
- uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0);
+ uint8 *twm = _vm->resource()->fileData("twmusic.pak", 0);
Common::StackLock lock(_mutex);
if (!_parser) {
@@ -2665,7 +2967,7 @@ void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
delete[] twm;
}
-void SoundTowns::onTimer(void * data) {
+void SoundTowns::onTimer(void *data) {
SoundTowns *music = (SoundTowns *)data;
Common::StackLock lock(music->_mutex);
if (music->_parser)
@@ -2763,7 +3065,7 @@ void SoundPC98::playSoundEffect(uint8) {
// KYRA 2
SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) :
- Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0) {
+ Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) {
}
SoundTownsPC98_v2::~SoundTownsPC98_v2() {
@@ -2774,6 +3076,7 @@ SoundTownsPC98_v2::~SoundTownsPC98_v2() {
bool SoundTownsPC98_v2::init() {
_driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ?
TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS);
+ _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false;
_vm->checkCD();
// FIXME: While checking for 'track1.XXX(X)' looks like
// a good idea, we should definitely not be doing this
@@ -2786,7 +3089,6 @@ bool SoundTownsPC98_v2::init() {
(Common::File::exists("track1.mp3") || Common::File::exists("track1.ogg") ||
Common::File::exists("track1.flac") || Common::File::exists("track1.fla")))
_musicEnabled = 2;
- _musicEnabled = 1;
return _driver->init();
}
@@ -2798,7 +3100,7 @@ void SoundTownsPC98_v2::playTrack(uint8 track) {
if (track == _lastTrack && _musicEnabled)
return;
- const uint16 * const cdaTracks = (const uint16 * const) cdaData();
+ const uint16 *const cdaTracks = (const uint16 *const) cdaData();
int trackNum = -1;
if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
@@ -2815,6 +3117,7 @@ void SoundTownsPC98_v2::playTrack(uint8 track) {
char musicfile[13];
sprintf(musicfile, fileListEntry(0), track);
delete[] _musicTrackData;
+
_musicTrackData = _vm->resource()->fileData(musicfile, 0);
_driver->loadData(_musicTrackData, true);
@@ -2854,8 +3157,8 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) {
char filename[13];
sprintf(filename, "%s.PCM", file);
- uint8 * data = _vm->resource()->fileData(filename, 0);
- uint8 * src = data;
+ uint8 *data = _vm->resource()->fileData(filename, 0);
+ uint8 *src = data;
uint16 sfxRate = rates[READ_LE_UINT16(src)];
src += 2;
@@ -2908,6 +3211,18 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, bool) {
return 1;
}
+void SoundTownsPC98_v2::playSoundEffect(uint8 track) {
+ if (!_useFmSfx)
+ return;
+
+ uint8 *sd = _vm->resource()->fileData("sound.dat", 0);
+
+
+ //TODO
+
+ delete [] sd;
+}
+
} // end of namespace Kyra
#undef EUPHONY_FADEOUT_TICKS