aboutsummaryrefslogtreecommitdiff
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_midi.cpp343
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_midi.h2
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp191
3 files changed, 277 insertions, 259 deletions
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index e22182632e..6843a35ce3 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -51,40 +51,40 @@ public:
int checkPriority(int pri);
private:
- struct StateA {
- uint8 numLoop;
- int32 fld_1;
+ struct EffectState {
+ uint8 envState;
+ int32 envStepLen;
int32 duration;
- uint16 fld_9;
- int32 effectState;
- uint8 fld_11;
- uint8 ar1[4];
- uint8 ar2[4];
+ int32 envTargetLevel;
+ int32 currentLevel;
+ uint8 loop;
+ uint8 envStepping[4];
+ uint8 envMod[4];
int8 modWheelSensitivity;
int8 modWheelState;
int8 modWheelLast;
- uint16 fld_1d;
- uint32 fld_21;
- int32 fld_25;
+ uint16 envStateNumSteps;
+ uint32 envStateStepCounter;
+ int32 envChangePerStep;
int8 dir;
- uint32 fld_2a;
- uint32 fld_2e;
- } *_stateA;
+ uint32 envChangePerStepRem;
+ uint32 envChangeCountRem;
+ } *_effectStates;
- struct StateB {
- int32 inc;
+ struct EffectDef {
+ int32 phase;
uint8 type;
uint8 useModWheel;
- uint8 fld_6;
- StateA *a;
- } *_stateB;
+ uint8 loopRefresh;
+ EffectState *s;
+ } *_effectDefs;
- int16 getEffectState(uint8 type);
- void initEffect(StateA *a, const uint8 *effectData);
- void updateEffectOuter3(StateA *a, StateB *b);
- int updateEffectOuter(StateA *a, StateB *b);
- void updateEffect(StateA *a);
- int lookupVolume(int a, int b);
+ int16 getEffectLevel(uint8 type);
+ void initEffect(EffectState *s, const uint8 *effectData);
+ void updateEffectGenerator(EffectState *s, EffectDef *d);
+ int updateEffectEnvelope(EffectState *s, EffectDef *d);
+ void updateEffect(EffectState *s);
+ int calcModWheelLevel(int lvl, int mod);
void keyOn();
void keyOff();
@@ -97,8 +97,8 @@ private:
uint8 _adjustModTl;
uint8 _chan;
uint8 _note;
- uint8 _carrierTl;
- uint8 _modulatorTl;
+ uint8 _operator2Tl;
+ uint8 _operator1Tl;
uint8 _sustainNoteOff;
int16 _duration;
@@ -109,8 +109,8 @@ private:
static const uint8 _chanMap[];
static const uint8 _chanMap2[];
- static const uint8 _effectDefs[];
- static const uint16 _effectData[];
+ static const uint8 _effectDefaults[];
+ static const uint16 _effectEnvStepTable[];
static const uint8 _freqMSB[];
static const uint16 _freqLSB[];
};
@@ -215,18 +215,19 @@ uint8 TownsMidiChanState::get(uint8 type) {
}
TownsMidiOutputChannel::TownsMidiOutputChannel(MidiDriver_TOWNS *driver, int chanIndex) : _driver(driver), _chan(chanIndex),
- _in(0), _prev(0), _next(0), _adjustModTl(0), _carrierTl(0), _note(0), _modulatorTl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) {
- _stateA = new StateA[2];
- memset(_stateA, 0, 2 * sizeof(StateA));
- _stateB = new StateB[2];
- memset(_stateB, 0, 2 * sizeof(StateB));
- _stateB[0].a = &_stateA[1];
- _stateB[1].a = &_stateA[0];
+ _in(0), _prev(0), _next(0), _adjustModTl(0), _operator2Tl(0), _note(0), _operator1Tl(0), _sustainNoteOff(0), _duration(0), _freq(0), _freqAdjust(0) {
+ _effectStates = new EffectState[2];
+ _effectDefs = new EffectDef[2];
+
+ memset(_effectStates, 0, 2 * sizeof(EffectState));
+ memset(_effectDefs, 0, 2 * sizeof(EffectDef));
+ _effectDefs[0].s = &_effectStates[1];
+ _effectDefs[1].s = &_effectStates[0];
}
TownsMidiOutputChannel::~TownsMidiOutputChannel() {
- delete[] _stateA;
- delete[] _stateB;
+ delete[] _effectStates;
+ delete[] _effectDefs;
}
void TownsMidiOutputChannel::noteOn(uint8 msb, uint16 lsb) {
@@ -243,9 +244,8 @@ void TownsMidiOutputChannel::noteOnPitchBend(uint8 msb, uint16 lsb) {
void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, uint8 tLevelPara) {
// 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.
- // There are no FM-TOWNS specific programs. This is the reason for the FM-TOWNS
- // music being so bad compared to AdLib (unsuitable data is just forced into the
- // wrong audio device).
+ // There are no FM-TOWNS specific programs. This is the reason for the low quality of the FM-TOWNS
+ // music (unsuitable data is just forced into the wrong audio device).
static const uint8 mul[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 };
uint8 chan = _chanMap[_chan];
@@ -295,50 +295,50 @@ void TownsMidiOutputChannel::setupProgram(const uint8 *data, uint8 mLevelPara, u
}
void TownsMidiOutputChannel::setupEffects(int index, uint8 flags, const uint8 *effectData) {
- uint16 maxVal[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F };
+ uint16 effectTargetLevel[] = { 0x2FF, 0x1F, 0x07, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3F, 0x0F, 0x0F, 0x0F, 0x03, 0x3E, 0x1F };
uint8 effectType[] = { 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->inc = 0;
- b->useModWheel = flags & 0x40;
- a->fld_11 = flags & 0x20;
- b->fld_6 = flags & 0x10;
- b->type = effectType[flags & 0x0f];
- a->fld_9 = maxVal[flags & 0x0f];
- a->modWheelSensitivity = 31;
- a->modWheelState = b->useModWheel ? _in->_modWheel >> 2 : 31;
-
- switch (b->type) {
+ EffectState *s = &_effectStates[index];
+ EffectDef *d = &_effectDefs[index];
+
+ d->phase = 0;
+ d->useModWheel = flags & 0x40;
+ s->loop = flags & 0x20;
+ d->loopRefresh = flags & 0x10;
+ d->type = effectType[flags & 0x0f];
+ s->envTargetLevel = effectTargetLevel[flags & 0x0f];
+ s->modWheelSensitivity = 31;
+ s->modWheelState = d->useModWheel ? _in->_modWheel >> 2 : 31;
+
+ switch (d->type) {
case 0:
- a->effectState = _carrierTl;
+ s->currentLevel = _operator2Tl;
break;
case 13:
- a->effectState = _modulatorTl;
+ s->currentLevel = _operator1Tl;
break;
case 30:
- a->effectState = 31;
- b->a->modWheelState = 0;
+ s->currentLevel = 31;
+ d->s->modWheelState = 0;
break;
case 31:
- a->effectState = 0;
- b->a->modWheelSensitivity = 0;
+ s->currentLevel = 0;
+ d->s->modWheelSensitivity = 0;
break;
default:
- a->effectState = getEffectState(b->type);
+ s->currentLevel = getEffectLevel(d->type);
break;
}
- initEffect(a, effectData);
+ initEffect(s, effectData);
}
void TownsMidiOutputChannel::setModWheel(uint8 value) {
- if (_stateA[0].numLoop && _stateB[0].type)
- _stateA[0].modWheelState = value >> 2;
+ if (_effectStates[0].envState && _effectDefs[0].type)
+ _effectStates[0].modWheelState = value >> 2;
- if (_stateA[1].numLoop && _stateB[1].type)
- _stateA[1].modWheelState = value >> 2;
+ if (_effectStates[1].envState && _effectDefs[1].type)
+ _effectStates[1].modWheelState = value >> 2;
}
void TownsMidiOutputChannel::connect(TownsMidiInputChannel *chan) {
@@ -381,8 +381,8 @@ bool TownsMidiOutputChannel::update() {
}
for (int i = 0; i < 2; i++) {
- if (_stateA[i].numLoop)
- updateEffectOuter3(&_stateA[i], &_stateB[i]);
+ if (_effectStates[i].envState)
+ updateEffectGenerator(&_effectStates[i], &_effectDefs[i]);
}
return false;
@@ -398,7 +398,7 @@ int TownsMidiOutputChannel::checkPriority(int pri) {
return kHighPriority;
}
-int16 TownsMidiOutputChannel::getEffectState(uint8 type) {
+int16 TownsMidiOutputChannel::getEffectLevel(uint8 type) {
uint8 chan = (type < 13) ? _chanMap2[_chan] : ((type < 26) ? _chanMap[_chan] : _chan);
if (type == 28)
@@ -411,45 +411,45 @@ int16 TownsMidiOutputChannel::getEffectState(uint8 type) {
type -= 13;
int32 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;
+ uint8 cs = (_driver->_chanState[chan].get(_effectDefaults[type * 4] >> 5) & _effectDefaults[type * 4 + 2]) >> _effectDefaults[type * 4 + 1];
+ if (_effectDefaults[type * 4 + 3])
+ res = _effectDefaults[type * 4 + 3] - cs;
return res;
}
-void TownsMidiOutputChannel::initEffect(StateA *a, const uint8 *effectData) {
- a->numLoop = 1;
- a->fld_1 = 0;
- a->modWheelLast = 31;
- a->duration = effectData[0] * 63;
- a->ar1[0] = effectData[1];
- a->ar1[1] = effectData[3];
- a->ar1[2] = effectData[5];
- a->ar1[3] = effectData[6];
- a->ar2[0] = effectData[2];
- a->ar2[1] = effectData[4];
- a->ar2[2] = 0;
- a->ar2[3] = effectData[7];
- updateEffect(a);
+void TownsMidiOutputChannel::initEffect(EffectState *s, const uint8 *effectData) {
+ s->envState = 1;
+ s->envStepLen = 0;
+ s->modWheelLast = 31;
+ s->duration = effectData[0] * 63;
+ s->envStepping[0] = effectData[1];
+ s->envStepping[1] = effectData[3];
+ s->envStepping[2] = effectData[5];
+ s->envStepping[3] = effectData[6];
+ s->envMod[0] = effectData[2];
+ s->envMod[1] = effectData[4];
+ s->envMod[2] = 0;
+ s->envMod[3] = effectData[7];
+ updateEffect(s);
}
-void TownsMidiOutputChannel::updateEffectOuter3(StateA *a, StateB *b) {
- uint8 f = updateEffectOuter(a, b);
+void TownsMidiOutputChannel::updateEffectGenerator(EffectState *s, EffectDef *d) {
+ uint8 f = updateEffectEnvelope(s, d);
if (f & 1) {
- switch (b->type) {
+ switch (d->type) {
case 0:
- _carrierTl = a->effectState + b->inc; /*???*/
+ _operator2Tl = s->currentLevel + d->phase;
break;
case 13:
- _modulatorTl = a->effectState + b->inc; /*???*/
+ _operator1Tl = s->currentLevel + d->phase;
break;
case 30:
- b->a->modWheelState = b->inc;
+ d->s->modWheelState = d->phase;
break;
case 31:
- b->a->modWheelSensitivity = b->inc;
+ d->s->modWheelSensitivity = d->phase;
break;
default:
break;
@@ -457,60 +457,60 @@ void TownsMidiOutputChannel::updateEffectOuter3(StateA *a, StateB *b) {
}
if (f & 2) {
- if (b->fld_6)
+ if (d->loopRefresh)
keyOn();
}
}
-int TownsMidiOutputChannel::updateEffectOuter(StateA *a, StateB *b) {
- if (a->duration) {
- a->duration -= 17;
- if (a->duration <= 0) {
- a->numLoop = 0;
+int TownsMidiOutputChannel::updateEffectEnvelope(EffectState *s, EffectDef *d) {
+ if (s->duration) {
+ s->duration -= 17;
+ if (s->duration <= 0) {
+ s->envState = 0;
return 0;
}
}
- int32 t = a->fld_1 + a->fld_25;
+ int32 t = s->envStepLen + s->envChangePerStep;
- a->fld_2e += a->fld_2a;
- if (a->fld_2e >= a->fld_1d) {
- a->fld_2e -= a->fld_1d;
- t += a->dir;
+ s->envChangeCountRem += s->envChangePerStepRem;
+ if (s->envChangeCountRem >= s->envStateNumSteps) {
+ s->envChangeCountRem -= s->envStateNumSteps;
+ t += s->dir;
}
int retFlags = 0;
- if (t != a->fld_1 || a->modWheelState != a->modWheelLast) {
- a->fld_1 = t;
- a->modWheelLast = a->modWheelState;
- t = lookupVolume(t, a->modWheelState);
- if (t != b->inc)
- b->inc = t;
+ if (t != s->envStepLen || (s->modWheelState != s->modWheelLast)) {
+ s->envStepLen = t;
+ s->modWheelLast = s->modWheelState;
+ t = calcModWheelLevel(t, s->modWheelState);
+ if (t != d->phase)
+ d->phase = t;
retFlags |= 1;
}
- if (--a->fld_21)
+ if (--s->envStateStepCounter)
return retFlags;
- if (++a->numLoop > 4) {
- if (!a->fld_11) {
- a->numLoop = 0;
+ if (++s->envState > 4) {
+ if (!s->loop) {
+ s->envState = 0;
return retFlags;
}
- a->numLoop = 1;
+ s->envState = 1;
retFlags |= 2;
}
- updateEffect(a);
+ updateEffect(s);
return retFlags;
}
-void TownsMidiOutputChannel::updateEffect(StateA *a) {
- uint8 c = a->numLoop - 1;
- uint8 v = a->ar1[c];
- int32 e = _effectData[_driver->_chanEffectLevel[((v & 0x7f) << 5) + a->modWheelSensitivity]];
+void TownsMidiOutputChannel::updateEffect(EffectState *s) {
+ uint8 st= s->envState - 1;
+ uint8 v = s->envStepping[st];
+ int32 e = _effectEnvStepTable[_driver->_chanEffectLevelModifier[((v & 0x7f) << 5) + s->modWheelSensitivity]];
if (v & 0x80)
e = _driver->randomValue(e);
@@ -518,58 +518,59 @@ void TownsMidiOutputChannel::updateEffect(StateA *a) {
if (!e)
e = 1;
- a->fld_1d = a->fld_21 = e;
+ s->envStateNumSteps = s->envStateStepCounter = e;
int32 d = 0;
- if (c != 2) {
- v = a->ar2[c];
- e = lookupVolume(a->fld_9, (v & 0x7f) - 31);
+ if (st != 2) {
+ v = s->envMod[st];
+ e = calcModWheelLevel(s->envTargetLevel, (v & 0x7f) - 31);
if (v & 0x80)
e = _driver->randomValue(e);
- if (e + a->effectState > a->fld_9) {
- e = a->fld_9 - a->effectState;
+ if (e + s->currentLevel > s->envTargetLevel) {
+ e = s->envTargetLevel - s->currentLevel;
} else {
- if (e + a->effectState + 1 <= 0)
- e = -a->effectState;
+ if (e + s->currentLevel + 1 <= 0)
+ e = -s->currentLevel;
}
- d = e - a->fld_1;
+ d = e - s->envStepLen;
}
- a->fld_25 = d / a->fld_1d;
- a->dir = (d < 0) ? -1 : 1;
- d *= a->dir;
- a->fld_2a = d % a->fld_1d;
- a->fld_2e = 0;
+ s->envChangePerStep = d / s->envStateNumSteps;
+ s->dir = (d < 0) ? -1 : 1;
+ d *= s->dir;
+ s->envChangePerStepRem = d % s->envStateNumSteps;
+ s->envChangeCountRem = 0;
}
-int TownsMidiOutputChannel::lookupVolume(int a, int b) {
- if (b == 0)
+int TownsMidiOutputChannel::calcModWheelLevel(int lvl, int mod) {
+ if (mod == 0)
return 0;
- if (b == 31)
- return a;
+ if (mod == 31)
+ return lvl;
- if (a > 63 || a < -63)
- return ((a + 1) * b) >> 5;
+ if (lvl > 63 || lvl < -63)
+ return ((lvl + 1) * mod) >> 5;
- if (b < 0) {
- if (a < 0)
- return _driver->_chanEffectLevel[((-a) << 5) - b];
+ if (mod < 0) {
+ if (mod < 0)
+ return _driver->_chanEffectLevelModifier[((-lvl) << 5) - mod];
else
- return -_driver->_chanEffectLevel[(a << 5) - b];
+ return -_driver->_chanEffectLevelModifier[(lvl << 5) - mod];
} else {
- if (a < 0)
- return -_driver->_chanEffectLevel[((-a) << 5) + b];
+ if (mod < 0)
+ return -_driver->_chanEffectLevelModifier[((-lvl) << 5) + mod];
else
- return _driver->_chanEffectLevel[((-a) << 5) + b];
+ return _driver->_chanEffectLevelModifier[((-lvl) << 5) + mod];
}
+
+ return 0;
}
void TownsMidiOutputChannel::keyOn() {
- // This driver uses only 2 operators since it is just a modified AdLib driver.
out(0x28, 0x30);
}
@@ -578,12 +579,11 @@ void TownsMidiOutputChannel::keyOff() {
}
void TownsMidiOutputChannel::keyOnSetFreq(uint16 frq) {
- uint8 t = (frq << 1) >> 8;
- frq = (_freqMSB[t] << 11) | _freqLSB[t] ;
+ uint16 note = (frq << 1) >> 8;
+ frq = (_freqMSB[note] << 11) | _freqLSB[note] ;
out(0xa4, frq >> 8);
out(0xa0, frq & 0xff);
- out(0x28, 0);
- // This driver uses only 2 operators since it is just a modified AdLib driver.
+ //out(0x28, 0x00);
out(0x28, 0x30);
}
@@ -607,7 +607,7 @@ const uint8 TownsMidiOutputChannel::_chanMap2[] = {
3, 4, 5, 11, 12, 13
};
-const uint8 TownsMidiOutputChannel::_effectDefs[] = {
+const uint8 TownsMidiOutputChannel::_effectDefaults[] = {
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,
@@ -615,7 +615,7 @@ const uint8 TownsMidiOutputChannel::_effectDefs[] = {
0x20, 0x04, 0x10, 0x00, 0xC0, 0x00, 0x01, 0x00, 0xC0, 0x01, 0x0E, 0x00
};
-const uint16 TownsMidiOutputChannel::_effectData[] = {
+const uint16 TownsMidiOutputChannel::_effectEnvStepTable[] = {
0x0001, 0x0002, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009,
0x000A, 0x000C, 0x000E, 0x0010, 0x0012, 0x0015, 0x0018, 0x001E,
0x0024, 0x0032, 0x0040, 0x0052, 0x0064, 0x0088, 0x00A0, 0x00C0,
@@ -714,26 +714,26 @@ void TownsMidiInputChannel::noteOn(byte note, byte velocity) {
oc->_sustainNoteOff = 0;
oc->_duration = _instrument[29] * 63;
- oc->_modulatorTl = (_instrument[1] & 0x3f) + _driver->_chanEffectLevel[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
- if (oc->_modulatorTl > 63)
- oc->_modulatorTl = 63;
+ oc->_operator1Tl = (_instrument[1] & 0x3f) + _driver->_chanEffectLevelModifier[((velocity >> 1) << 5) + (_instrument[4] >> 2)];
+ if (oc->_operator1Tl > 63)
+ oc->_operator1Tl = 63;
- oc->_carrierTl = (_instrument[6] & 0x3f) + _driver->_chanEffectLevel[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
- if (oc->_carrierTl > 63)
- oc->_carrierTl = 63;
+ oc->_operator2Tl = (_instrument[6] & 0x3f) + _driver->_chanEffectLevelModifier[((velocity >> 1) << 5) + (_instrument[9] >> 2)];
+ if (oc->_operator2Tl > 63)
+ oc->_operator2Tl = 63;
- oc->setupProgram(_instrument, oc->_adjustModTl == 1 ? _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_modulatorTl << 5)]] : oc->_modulatorTl, _programAdjustLevel[_driver->_chanEffectLevel[(_tl >> 2) + (oc->_carrierTl << 5)]]);
+ oc->setupProgram(_instrument, oc->_adjustModTl == 1 ? _programAdjustLevel[_driver->_chanEffectLevelModifier[(_tl >> 2) + (oc->_operator1Tl << 5)]] : oc->_operator1Tl, _programAdjustLevel[_driver->_chanEffectLevelModifier[(_tl >> 2) + (oc->_operator2Tl << 5)]]);
oc->noteOn(note + _transpose, _freqLSB);
if (_instrument[11] & 0x80)
oc->setupEffects(0, _instrument[11], &_instrument[12]);
else
- oc->_stateA[0].numLoop = 0;
+ oc->_effectStates[0].envState = 0;
if (_instrument[20] & 0x80)
oc->setupEffects(1, _instrument[20], &_instrument[21]);
else
- oc->_stateA[1].numLoop = 0;
+ oc->_effectStates[1].envState = 0;
}
void TownsMidiInputChannel::programChange(byte program) {
@@ -795,7 +795,6 @@ void TownsMidiInputChannel::controlModulationWheel(byte value) {
void TownsMidiInputChannel::controlVolume(byte value) {
/* This is all done inside the imuse code
-
uint16 v1 = _ctrlVolume + 1;
uint16 v2 = value;
if (_chanIndex != 16) {
@@ -805,10 +804,6 @@ void TownsMidiInputChannel::controlVolume(byte value) {
_tl = (v1 * v2) >> 7;*/
_tl = value;
-
- /* nullsub
- _out->setVolume(_tl);
- */
}
void TownsMidiInputChannel::controlPanPos(byte value) {
@@ -865,13 +860,13 @@ int MidiDriver_TOWNS::open() {
_chanState = new TownsMidiChanState[32];
- _chanEffectLevel = new uint8[2048];
+ _chanEffectLevelModifier = new uint8[2048];
for (int i = 0; i < 64; i++) {
for (int ii = 0; ii < 32; ii++)
- _chanEffectLevel[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff;
+ _chanEffectLevelModifier[(i << 5) + ii] = ((i * (ii + 1)) >> 5) & 0xff;
}
for (int i = 0; i < 64; i++)
- _chanEffectLevel[i << 5] = 0;
+ _chanEffectLevelModifier[i << 5] = 0;
_intf->callback(0);
@@ -916,8 +911,8 @@ void MidiDriver_TOWNS::close() {
delete[] _chanState;
_chanState = 0;
- delete[] _chanEffectLevel;
- _chanEffectLevel = 0;
+ delete[] _chanEffectLevelModifier;
+ _chanEffectLevelModifier = 0;
}
void MidiDriver_TOWNS::send(uint32 b) {
diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.h b/audio/softsynth/fmtowns_pc98/towns_midi.h
index 8dc71f3528..52298d77ce 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.h
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.h
@@ -78,7 +78,7 @@ private:
bool _open;
- uint8 *_chanEffectLevel;
+ uint8 *_chanEffectLevelModifier;
};
#endif
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index 263986ec0c..09d3ca3b8d 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -39,45 +39,22 @@ public:
void recalculateRates();
void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out);
- void feedbackLevel(int32 level) {
- _feedbackLevel = level ? level + 6 : 0;
- }
- void detune(int value) {
- _detn = &_detnTbl[value << 5];
- }
- void multiple(uint32 value) {
- _multiple = value ? (value << 1) : 1;
- }
- void attackRate(uint32 value) {
- _specifiedAttackRate = value;
- }
+ void feedbackLevel(int32 level);
+ void detune(int value);
+ void multiple(uint32 value);
+ void attackRate(uint32 value);
bool scaleRate(uint8 value);
- void decayRate(uint32 value) {
- _specifiedDecayRate = value;
- recalculateRates();
- }
- void sustainRate(uint32 value) {
- _specifiedSustainRate = value;
- recalculateRates();
- }
- void sustainLevel(uint32 value) {
- _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5;
- }
- void releaseRate(uint32 value) {
- _specifiedReleaseRate = value;
- recalculateRates();
- }
- void totalLevel(uint32 value) {
- _totalLevel = value << 3;
- }
- void ampModulation(bool enable) {
- _ampMod = enable;
- }
+ void decayRate(uint32 value);
+ void sustainRate(uint32 value);
+ void sustainLevel(uint32 value);
+ void releaseRate(uint32 value);
+ void totalLevel(uint32 value);
+ void ampModulation(bool enable);
void reset();
protected:
EnvelopeState _state;
- bool _playing;
+ bool _holdKey;
uint32 _feedbackLevel;
uint32 _multiple;
uint32 _totalLevel;
@@ -122,7 +99,7 @@ TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, con
_rtt(rtt), _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable),
_sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2),
_specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0),
- _phase(0), _state(kEnvReady), _playing(false), _timer(0), _keyScale1(0),
+ _phase(0), _state(kEnvReady), _holdKey(false), _timer(0), _keyScale1(0),
_keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(0) {
fs_a.rate = fs_a.shift = fs_d.rate = fs_d.shift = fs_s.rate = fs_s.shift = fs_r.rate = fs_r.shift = 0;
@@ -131,19 +108,19 @@ TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, con
}
void TownsPC98_FmSynthOperator::keyOn() {
- if (_playing)
+ if (_holdKey)
return;
- _playing = true;
+ _holdKey = true;
_state = kEnvAttacking;
_phase = 0;
}
void TownsPC98_FmSynthOperator::keyOff() {
- if (!_playing)
+ if (!_holdKey)
return;
- _playing = false;
+ _holdKey = false;
if (_state != kEnvReady)
_state = kEnvReleasing;
}
@@ -199,39 +176,42 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3
int32 targetLevel = 0;
EnvelopeState nextState = kEnvReady;
- switch (_state) {
- case kEnvReady:
- return;
- case kEnvAttacking:
- targetLevel = 0;
- nextState = kEnvDecaying;
- if ((_specifiedAttackRate << 1) + _keyScale2 < 64) {
- targetTime = (1 << fs_a.shift) - 1;
- levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4;
+ for (bool loop = true; loop;) {
+ switch (_state) {
+ case kEnvReady:
+ return;
+ case kEnvAttacking:
+ targetLevel = 0;
+ nextState = _sustainLevel ? kEnvDecaying : kEnvSustaining;
+ if ((_specifiedAttackRate << 1) + _keyScale2 < 62) {
+ targetTime = (1 << fs_a.shift) - 1;
+ levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4;
+ } else {
+ _currentLevel = targetLevel;
+ _state = nextState;
+ continue;
+ }
+ break;
+ case kEnvDecaying:
+ targetTime = (1 << fs_d.shift) - 1;
+ nextState = kEnvSustaining;
+ targetLevel = _sustainLevel;
+ levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)];
+ break;
+ case kEnvSustaining:
+ targetTime = (1 << fs_s.shift) - 1;
+ nextState = kEnvSustaining;
+ targetLevel = 1023;
+ levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)];
+ break;
+ case kEnvReleasing:
+ targetTime = (1 << fs_r.shift) - 1;
+ nextState = kEnvReady;
+ targetLevel = 1023;
+ levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)];
break;
- } else {
- _currentLevel = targetLevel;
- _state = nextState;
}
- // Fall through
- case kEnvDecaying:
- targetTime = (1 << fs_d.shift) - 1;
- nextState = kEnvSustaining;
- targetLevel = _sustainLevel;
- levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)];
- break;
- case kEnvSustaining:
- targetTime = (1 << fs_s.shift) - 1;
- nextState = kEnvSustaining;
- targetLevel = 1023;
- levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)];
- break;
- case kEnvReleasing:
- targetTime = (1 << fs_r.shift) - 1;
- nextState = kEnvReady;
- targetLevel = 1023;
- levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)];
- break;
+ loop = false;
}
if (!(_tickCount & targetTime)) {
@@ -272,6 +252,63 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3
out += *o;
}
+void TownsPC98_FmSynthOperator::feedbackLevel(int32 level) {
+ _feedbackLevel = level ? level + 6 : 0;
+}
+
+void TownsPC98_FmSynthOperator::detune(int value) {
+ _detn = &_detnTbl[value << 5];
+}
+
+void TownsPC98_FmSynthOperator::multiple(uint32 value) {
+ _multiple = value ? (value << 1) : 1;
+}
+
+void TownsPC98_FmSynthOperator::attackRate(uint32 value) {
+ _specifiedAttackRate = value;
+}
+
+bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) {
+ value = 3 - value;
+ if (_keyScale1 != value) {
+ _keyScale1 = value;
+ return true;
+ }
+
+ int k = _keyScale2;
+ int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
+ fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
+ fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
+ return false;
+}
+
+void TownsPC98_FmSynthOperator::decayRate(uint32 value) {
+ _specifiedDecayRate = value;
+ recalculateRates();
+}
+
+void TownsPC98_FmSynthOperator::sustainRate(uint32 value) {
+ _specifiedSustainRate = value;
+ recalculateRates();
+ }
+
+void TownsPC98_FmSynthOperator::sustainLevel(uint32 value) {
+ _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5;
+}
+
+void TownsPC98_FmSynthOperator::releaseRate(uint32 value) {
+ _specifiedReleaseRate = value;
+ recalculateRates();
+}
+
+void TownsPC98_FmSynthOperator::totalLevel(uint32 value) {
+ _totalLevel = value << 3;
+}
+
+void TownsPC98_FmSynthOperator::ampModulation(bool enable) {
+ _ampMod = enable;
+}
+
void TownsPC98_FmSynthOperator::reset() {
keyOff();
_timer = 0;
@@ -292,20 +329,6 @@ void TownsPC98_FmSynthOperator::reset() {
ampModulation(false);
}
-bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) {
- value = 3 - value;
- if (_keyScale1 != value) {
- _keyScale1 = value;
- return true;
- }
-
- int k = _keyScale2;
- int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
- fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
- fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
- return false;
-}
-
class TownsPC98_FmSynthSquareSineSource {
public:
TownsPC98_FmSynthSquareSineSource(const uint32 timerbase, const uint32 rtt);