NScumm.Core.Audio.SoftSynth.TownsMidiOutputChannel.SetupProgram C# (CSharp) Method

SetupProgram() public method

public SetupProgram ( byte data, byte mLevelPara, byte tLevelPara ) : void
data byte
mLevelPara byte
tLevelPara byte
return void
        public void SetupProgram(byte[] data, byte mLevelPara, byte 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 low quality of the FM-TOWNS
            // music (unsuitable data is just forced into the wrong audio device).

            byte[] mul = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 };
            byte chan = _chanMap[_chan];

            byte mulAmsFms1 = _driver._chanState[chan].mulAmsFms = data[0];
            byte tl1 = _driver._chanState[chan].tl = (byte)((data[1] | 0x3f) - mLevelPara);
            byte attDec1 = _driver._chanState[chan].attDec = (byte)~data[2];
            byte sus1 = _driver._chanState[chan].sus = (byte)~data[3];
            _driver._chanState[chan].unk2 = data[4];
            chan += 3;

            @out(0x30, mul[mulAmsFms1 & 0x0f]);
            @out(0x40, (byte)((tl1 & 0x3f) + 15));
            @out(0x50, (byte)(((attDec1 >> 4) << 1) | ((attDec1 >> 4) & 1)));
            @out(0x60, (byte)(((attDec1 << 1) | (attDec1 & 1)) & 0x1f));
            @out(0x70, (byte)((((mulAmsFms1 & 0x20) ^ 0x20) != 0) ? (((sus1 & 0x0f) << 1) | 1) : 0));
            @out(0x80, sus1);

            byte mulAmsFms2 = _driver._chanState[chan].mulAmsFms = data[5];
            byte tl2 = _driver._chanState[chan].tl = (byte)((data[6] | 0x3f) - tLevelPara);
            byte attDec2 = _driver._chanState[chan].attDec = (byte)~data[7];
            byte sus2 = _driver._chanState[chan].sus = (byte)~data[8];
            _driver._chanState[chan].unk2 = data[9];

            byte mul2 = mul[mulAmsFms2 & 0x0f];
            tl2 = (byte)((tl2 & 0x3f) + 15);
            byte ar2 = (byte)(((attDec2 >> 4) << 1) | ((attDec2 >> 4) & 1));
            byte dec2 = (byte)(((attDec2 << 1) | (attDec2 & 1)) & 0x1f);
            byte sus2r = (byte)((((mulAmsFms2 & 0x20) ^ 0x20) != 0) ? (((sus2 & 0x0f) << 1) | 1) : 0);

            for (int i = 4; i < 16; i += 4)
            {
                @out((byte)(0x30 + i), mul2);
                @out((byte)(0x40 + i), tl2);
                @out((byte)(0x50 + i), ar2);
                @out((byte)(0x60 + i), dec2);
                @out((byte)(0x70 + i), sus2r);
                @out((byte)(0x80 + i), sus2);
            }

            _driver._chanState[chan].fgAlg = data[10];

            byte alg = (byte)(5 + 2 * (data[10] & 1));
            byte fb = (byte)(4 * (data[10] & 0x0e));
            @out(0xb0, (byte)(fb | alg));
            byte t = (byte)(mulAmsFms1 | mulAmsFms2);
            @out(0xb4, (byte)(0xc0 | ((t & 0x80) >> 3) | ((t & 0x40) >> 5)));
        }

Usage Example

Example #1
0
        public override void NoteOn(byte note, byte velocity)
        {
            TownsMidiOutputChannel oc = _driver.AllocateOutputChannel(_priority);

            if (oc == null)
            {
                return;
            }

            oc.Connect(this);

            oc._adjustModTl    = (byte)(_instrument[10] & 1);
            oc._note           = note;
            oc._sustainNoteOff = 0;
            oc._duration       = (short)(_instrument[29] * 63);

            oc._operator1Tl = (byte)((_instrument[1] & 0x3f) + _driver._operatorLevelTable[((velocity >> 1) << 5) + (_instrument[4] >> 2)]);
            if (oc._operator1Tl > 63)
            {
                oc._operator1Tl = 63;
            }

            oc._operator2Tl = (byte)((_instrument[6] & 0x3f) + _driver._operatorLevelTable[((velocity >> 1) << 5) + (_instrument[9] >> 2)]);
            if (oc._operator2Tl > 63)
            {
                oc._operator2Tl = 63;
            }

            oc.SetupProgram(_instrument, oc._adjustModTl == 1 ? _programAdjustLevel[_driver._operatorLevelTable[(_tl >> 2) + (oc._operator1Tl << 5)]] : oc._operator1Tl, _programAdjustLevel[_driver._operatorLevelTable[(_tl >> 2) + (oc._operator2Tl << 5)]]);
            oc.NoteOn((byte)(note + _transpose), _freqLSB);

            if ((_instrument[11] & 0x80) != 0)
            {
                oc.SetupEffects(0, _instrument[11], _instrument, 12);
            }
            else
            {
                oc._effectEnvelopes[0].state = EnvelopeState.Ready;
            }

            if ((_instrument[20] & 0x80) != 0)
            {
                oc.SetupEffects(1, _instrument[20], _instrument, 21);
            }
            else
            {
                oc._effectEnvelopes[1].state = EnvelopeState.Ready;
            }
        }