File size: 4,586 Bytes
b0bfea8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import { SpessaSynthInfo } from "./loggin.js";
import { consoleColors } from "./other.js";
import { DEFAULT_PERCUSSION } from "../synthetizer/synth_constants.js";

export const XG_SFX_VOICE = 64;

const GM2_DEFAULT_BANK = 121;

/**
 * @param sys {SynthSystem}
 * @returns {number}
 */
export function getDefaultBank(sys)
{
    return sys === "gm2" ? GM2_DEFAULT_BANK : 0;
}

/**
 * @param bankNr {number}
 * @returns {boolean}
 */
export function isXGDrums(bankNr)
{
    return bankNr === 120 || bankNr === 126 || bankNr === 127;
}

/**
 * @param bank {number}
 * @returns {boolean}
 */
export function isValidXGMSB(bank)
{
    return isXGDrums(bank) || bank === XG_SFX_VOICE || bank === GM2_DEFAULT_BANK;
}

/**
 * Bank select hacks abstracted here
 * @param bankBefore {number} the current bank number
 * @param bank {number} the cc change bank number
 * @param system {SynthSystem} MIDI system
 * @param isLSB {boolean} is bank LSB?
 * @param isDrums {boolean} is drum channel?
 * @param channelNumber {number} channel number
 * @returns {{
 *     newBank: number,
 *     drumsStatus: 0|1|2
 * }} 0 - unchanged, 1 - OFF, 2 - ON
 */
export function parseBankSelect(bankBefore, bank, system, isLSB, isDrums, channelNumber)
{
    // 64 means SFX in MSB, so it is allowed
    let out = bankBefore;
    let drumsStatus = 0;
    if (isLSB)
    {
        if (isSystemXG(system))
        {
            if (!isValidXGMSB(bank))
            {
                out = bank;
            }
        }
        else if (system === "gm2")
        {
            out = bank;
        }
    }
    else
    {
        let canSetBankSelect = true;
        switch (system)
        {
            case "gm":
                // gm ignores bank select
                SpessaSynthInfo(
                    `%cIgnoring the Bank Select (${bank}), as the synth is in GM mode.`,
                    consoleColors.info
                );
                canSetBankSelect = false;
                break;
            
            case "xg":
                canSetBankSelect = isValidXGMSB(bank);
                // for xg, if msb is 120, 126 or 127, then it's drums
                if (isXGDrums(bank))
                {
                    drumsStatus = 2;
                }
                else
                {
                    // drums shall not be disabled on channel 9
                    if (channelNumber % 16 !== DEFAULT_PERCUSSION)
                    {
                        drumsStatus = 1;
                    }
                }
                break;
            
            case "gm2":
                if (bank === 120)
                {
                    drumsStatus = 2;
                }
                else
                {
                    if (channelNumber % 16 !== DEFAULT_PERCUSSION)
                    {
                        drumsStatus = 1;
                    }
                }
        }
        
        if (isDrums)
        {
            // 128 for percussion channel
            bank = 128;
        }
        if (bank === 128 && !isDrums)
        {
            // if a channel is not for percussion, default to bank current
            bank = bankBefore;
        }
        if (canSetBankSelect)
        {
            out = bank;
        }
    }
    return {
        newBank: out,
        drumsStatus: drumsStatus
    };
}


/**
 * Chooses a bank number according to spessasynth logic
 * That is:
 * for GS, bank MSB if not drum, otherwise 128
 * for XG: bank MSB if drum and MSB is valid, 128 othewise, bank MSB if it is SFX voice, LSB otherwise
 * @param msb {number}
 * @param lsb {number}
 * @param isDrums {boolean}
 * @param isXG {boolean}
 * @returns {number}
 */
export function chooseBank(msb, lsb, isDrums, isXG)
{
    if (isXG)
    {
        if (isDrums)
        {
            if (isXGDrums(msb))
            {
                return msb;
            }
            else
            {
                return 128;
            }
        }
        else
        {
            // check for SFX
            if (isValidXGMSB(msb))
            {
                return msb;
            }
            // if lsb is 0 and msb is not, use that
            if (lsb === 0 && msb !== 0)
            {
                return msb;
            }
            if (!isValidXGMSB(lsb))
            {
                return lsb;
            }
            return 0;
        }
    }
    else
    {
        return isDrums ? 128 : msb;
    }
}

/**
 * @param system {SynthSystem}
 * @returns boolean
 */
export function isSystemXG(system)
{
    return system === "gm2" || system === "xg";
}