diff options
author | athrxx | 2011-05-01 22:43:36 +0200 |
---|---|---|
committer | Willem Jan Palenstijn | 2011-05-17 20:33:03 +0200 |
commit | bd2c84be89068757531399b32e099ec7287ee2a6 (patch) | |
tree | 8155b82e2af6467a36bb249837eab54e8287862d /audio | |
parent | 25814e64ac091e70c1a5419c57184acb7dd05e8a (diff) | |
download | scummvm-rg350-bd2c84be89068757531399b32e099ec7287ee2a6.tar.gz scummvm-rg350-bd2c84be89068757531399b32e099ec7287ee2a6.tar.bz2 scummvm-rg350-bd2c84be89068757531399b32e099ec7287ee2a6.zip |
FM-TOWNS AUDIO: More midi driver code (effect processing)
Diffstat (limited to 'audio')
-rw-r--r-- | audio/softsynth/fmtowns_pc98/towns_midi.cpp | 206 | ||||
-rw-r--r-- | audio/softsynth/fmtowns_pc98/towns_midi.h | 11 |
2 files changed, 166 insertions, 51 deletions
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp index 81f561a84c..5b2dc7b48f 100644 --- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp +++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp @@ -25,6 +25,38 @@ #include "audio/softsynth/fmtowns_pc98/towns_midi.h" #include "common/textconsole.h" +struct ChanState { + uint8 get(uint8 type) { + switch (type) { + case 0: + return unk1; + case 1: + return mulAmsFms; + case 2: + return tl; + case 3: + return attDec; + case 4: + return sus; + case 5: + return fgAlg; + case 6: + return unk2; + default: + break; + } + return 0; + } + + uint8 unk1; + uint8 mulAmsFms; + uint8 tl; + uint8 attDec; + uint8 sus; + uint8 fgAlg; + uint8 unk2; +}; + class TownsMidiOutputChannel { friend class TownsMidiInputChannel; public: @@ -34,7 +66,7 @@ public: void noteOn(uint8 msb, uint16 lsb); void noteOnPitchBend(uint8 msb, uint16 lsb); void setupProgram(const uint8 *data, uint8 vol1, uint8 vol2); - void noteOnSubSubSub_s1(int index, uint8 c, const uint8 *instr); + void setupEffects(int index, uint8 c, const uint8 *effectData); void setModWheel(uint8 value); void connect(TownsMidiInputChannel *chan); @@ -48,6 +80,43 @@ public: int checkPriority(int pri); private: + struct StateA { + uint8 active; + uint8 fld_1; + uint8 fld_2; + uint8 fld_3; + uint8 fld_4; + uint8 fld_5; + uint8 fld_6; + uint8 fld_7; + uint8 fld_8; + uint32 fld_9; + uint32 effectState; + uint8 fld_11; + uint8 fld_12; + uint8 fld_13; + uint8 fld_14; + uint8 fld_15; + uint8 fld_16; + uint8 fld_17; + uint8 fld_18; + uint8 fld_19; + uint8 fld_1a; + uint8 modWheelImpact; + uint8 modWheel; + } *_stateA; + + struct StateB { + uint32 fld_0; + uint8 type; + uint8 useModWheel; + uint8 fld_6; + StateA *a; + } *_stateB; + + uint32 getEffectState(uint8 type); + void processEffect(StateA *a, const uint8 *effectData); + void keyOn(); void keyOff(); void internKeySetFreq(uint16 frq); @@ -59,8 +128,8 @@ private: uint8 _fld_c; uint8 _chan; uint8 _note; - uint8 _tl2; - uint8 _tl1; + uint8 _carrierTl; + uint8 _modulatorTl; uint8 _sustainNoteOff; uint32 _duration; uint8 _fld_13; @@ -69,29 +138,11 @@ private: uint16 _freq; int16 _freqAdjust; - struct StateA { - uint8 active; - uint8 a[48]; - uint8 modWheel; - } *_stateA; - - struct StateB { - uint8 b1; - uint8 b2; - uint8 b3; - uint8 b4; - uint8 b5; - uint8 mwu; - uint8 b7; - uint8 b8; - uint8 b9; - uint8 b10; - uint8 b11; - } *_stateB; - MidiDriver_TOWNS *_driver; static const uint8 _chanMap[]; + static const uint8 _chanMap2[]; + static const uint8 _effectDefs[]; static const uint8 _freqMSB[]; static const uint16 _freqLSB[]; }; @@ -123,11 +174,10 @@ private: void controlVolume(byte value); void controlPanPos(byte value); void controlSustain(byte value); - void controlRelease(); + + void releasePedal(); TownsMidiOutputChannel *_outChan; - //TownsMidiInputChannel *_prev; - //TownsMidiInputChannel *_next; uint8 *_instrument; uint8 _prg; @@ -156,7 +206,7 @@ private: }; TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex), - _midi(0), _prev(0), _next(0), _fld_c(0), _tl2(0), _note(0), _tl1(0), _sustainNoteOff(0), _duration(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) { + _midi(0), _prev(0), _next(0), _fld_c(0), _carrierTl(0), _note(0), _modulatorTl(0), _sustainNoteOff(0), _duration(0), _fld_13(0), _prg(0), _freq(0), _freqAdjust(0) { _stateA = new StateA[2]; memset(_stateA, 0, 2 * sizeof(StateA)); _stateB = new StateB[2]; @@ -193,7 +243,7 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v uint8 tl1 = _driver->_chanState[chan].tl = (data[1] | 0x3f) - vol1; uint8 attDec1 = _driver->_chanState[chan].attDec = ~data[2]; uint8 sus1 = _driver->_chanState[chan].sus = ~data[3]; - uint8 unk1 = _driver->_chanState[chan].unk = data[4]; + uint8 unk1 = _driver->_chanState[chan].unk2 = data[4]; chan += 3; out(0x30, mul[mulAmsFms1 & 0x0f]); @@ -207,7 +257,7 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v uint8 tl2 = _driver->_chanState[chan].tl = (data[6] | 0x3f) - vol2; uint8 attDec2 = _driver->_chanState[chan].attDec = ~data[7]; uint8 sus2 = _driver->_chanState[chan].sus = ~data[8]; - uint8 unk2 = _driver->_chanState[chan].unk = data[9]; + uint8 unk2 = _driver->_chanState[chan].unk2 = data[9]; uint8 mul2 = mul[mulAmsFms2 & 0x0f]; tl2 = (tl2 & 0x3f) + 15; @@ -232,16 +282,50 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 vol1, uint8 v out(0xb4, 0xc0 | ((t & 0x80) >> 3) | ((t & 0x40) >> 5)); } -void TownsMidiOutputChannel::noteOnSubSubSub_s1(int index, uint8 c, const uint8 *instr) { +void TownsMidiOutputChannel::setupEffects(int index, uint8 c, const uint8 *effectData) { + uint16 maxVal[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F }; + uint8 para1[] = { 0x1D, 0x1C, 0x1B, 0x00, 0x03, 0x04, 0x07, 0x08, 0x0D, 0x10, 0x11, 0x14, 0x15, 0x1e, 0x1f, 0x00 }; + StateA *a = &_stateA[index]; StateB *b = &_stateB[index]; + + b->fld_0 = 0; + b->useModWheel = c & 0x40; + a->fld_11 = c & 0x20; + b->fld_6 = c & 0x10; + b->type = para1[c & 0x0f]; + a->fld_9 = maxVal[c & 0x0f]; + a->fld_1a = 0x1f; + a->modWheelImpact = b->useModWheel ? _midi->_modWheel >> 2 : 0x1f; + + switch (b->type) { + case 0: + a->effectState = _carrierTl; + break; + case 13: + a->effectState = _modulatorTl; + break; + case 30: + a->effectState = 0x1f; + b->a->modWheelImpact = 0; + break; + case 31: + a->effectState = 0; + b->a->fld_1a = 0; + break; + default: + a->effectState = getEffectState(b->type); + break; + } + + processEffect(a, effectData); } void TownsMidiOutputChannel::setModWheel(uint8 value) { - if (_stateA[0].active && _stateB[0].mwu) + if (_stateA[0].active && _stateB[0].type) _stateA[0].modWheel = value >> 2; - if (_stateA[1].active && _stateB[1].mwu) + if (_stateA[1].active && _stateB[1].type) _stateA[1].modWheel = value >> 2; } @@ -280,6 +364,30 @@ int TownsMidiOutputChannel::checkPriority(int pri) { return kHighPriority; } +uint32 TownsMidiOutputChannel::getEffectState(uint8 type) { + uint8 chan = (type < 13) ? _chanMap2[_chan] : ((type < 26) ? _chanMap[_chan] : _chan); + + if (type == 28) + return 15; + else if (type == 29) + return 383; + else if (type > 29) + return 0; + else if (type > 12) + type -= 13; + + uint32 res = 0; + uint8 cs = (_driver->_chanState[chan].get(_effectDefs[type * 4] >> 5) & _effectDefs[type * 4 + 2]) >> _effectDefs[type * 4 + 1]; + if (_effectDefs[type * 4 + 3]) + res = _effectDefs[type * 4 + 3] - cs; + + return res; +} + +void TownsMidiOutputChannel::processEffect(StateA *a, const uint8 *effectData) { + +} + void TownsMidiOutputChannel::keyOn() { // This driver uses only 2 operators and 2 algorithms (algorithm 5 and 7), // since it is just a modified AdLib driver. It also uses AdLib programs. @@ -323,6 +431,18 @@ const uint8 TownsMidiOutputChannel::_chanMap[] = { 0, 1, 2, 8, 9, 10 }; +const uint8 TownsMidiOutputChannel::_chanMap2[] = { + 3, 4, 5, 11, 12, 13 +}; + +const uint8 TownsMidiOutputChannel::_effectDefs[] = { + 0x40, 0x00, 0x3F, 0x3F, 0xE0, 0x02, 0x00, 0x00, 0x40, 0x06, 0xC0, 0x00, + 0x20, 0x00, 0x0F, 0x00, 0x60, 0x04, 0xF0, 0x0F, 0x60, 0x00, 0x0F, 0x0F, + 0x80, 0x04, 0xF0, 0x0F, 0x80, 0x00, 0x0F, 0x0F, 0xE0, 0x00, 0x03, 0x00, + 0x20, 0x07, 0x80, 0x00, 0x20, 0x06, 0x40, 0x00, 0x20, 0x05, 0x20, 0x00, + 0x20, 0x04, 0x10, 0x00, 0xC0, 0x00, 0x01, 0x00, 0xC0, 0x01, 0x0E, 0x00 +}; + const uint8 TownsMidiOutputChannel::_freqMSB[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -413,24 +533,24 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) { oc->_sustainNoteOff = 0; oc->_duration = _instrument[29] * 72; - oc->_tl1 = (_instrument[1] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)]; - if (oc->_tl1 > 63) - oc->_tl1 = 63; + oc->_modulatorTl = (_instrument[1] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)]; + if (oc->_modulatorTl > 63) + oc->_modulatorTl = 63; - oc->_tl2 = (_instrument[6] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[9] >> 2)]; - if (oc->_tl2 > 63) - oc->_tl2 = 63; + oc->_carrierTl = (_instrument[6] & 0x3f) + _driver->_chanOutputLevel[((velocity >> 1) << 5) + (_instrument[9] >> 2)]; + if (oc->_carrierTl > 63) + oc->_carrierTl = 63; - oc->setupProgram(_instrument, oc->_fld_c == 1 ? _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_tl1 << 5)]] : oc->_tl1, _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_tl2 << 5)]]); + oc->setupProgram(_instrument, oc->_fld_c == 1 ? _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_modulatorTl << 5)]] : oc->_modulatorTl, _programAdjustLevel[_driver->_chanOutputLevel[(_tl >> 2) + (oc->_carrierTl << 5)]]); oc->noteOn(note + _transpose, _freqLSB); if (_instrument[11] & 0x80) - oc->noteOnSubSubSub_s1(0, _instrument[11], &_instrument[12]); + oc->setupEffects(0, _instrument[11], &_instrument[12]); else oc->_stateA[0].active = 0; if (_instrument[20] & 0x80) - oc->noteOnSubSubSub_s1(1, _instrument[20], &_instrument[21]); + oc->setupEffects(1, _instrument[20], &_instrument[21]); else oc->_stateA[1].active = 0; } @@ -511,10 +631,10 @@ void TownsMidiInputChannel::controlPanPos(byte value) { void TownsMidiInputChannel::controlSustain(byte value) { _sustain = value; if (!value) - controlRelease(); + releasePedal(); } -void TownsMidiInputChannel::controlRelease() { +void TownsMidiInputChannel::releasePedal() { for (TownsMidiOutputChannel *oc = _outChan; oc; oc = oc->_next) { if (oc->_sustainNoteOff) oc->disconnect(); diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h index 6ff8a99cda..8cffdd71da 100644 --- a/audio/softsynth/fmtowns_pc98/towns_midi.h +++ b/audio/softsynth/fmtowns_pc98/towns_midi.h @@ -28,8 +28,10 @@ #include "audio/softsynth/fmtowns_pc98/towns_audio.h" #include "audio/mididrv.h" + class TownsMidiOutputChannel; class TownsMidiInputChannel; +struct ChanState; class MidiDriver_TOWNS : public MidiDriver, public TownsAudioInterfacePluginDriver { friend class TownsMidiInputChannel; @@ -61,14 +63,7 @@ private: TownsMidiInputChannel **_channels; TownsMidiOutputChannel **_out; - struct ChanState { - uint8 mulAmsFms; - uint8 tl; - uint8 attDec; - uint8 sus; - uint8 fgAlg; - uint8 unk; - } *_chanState; + ChanState *_chanState; Common::TimerManager::TimerProc _timerBproc; void *_timerBpara; |