spessasynth_lib 3.16.4 → 3.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,9 +19,10 @@
19
19
  * @param bankOffset {number} the bank offset for RMIDI
20
20
  * @param encoding {string} the encoding of the RMIDI info chunk
21
21
  * @param metadata {RMIDMetadata} the metadata of the file. Optional. If provided, the encoding is forced to utf-8/
22
+ * @param correctBankOffset {boolean}
22
23
  * @returns {IndexedByteArray}
23
24
  */
24
- export function writeRMIDI(soundfontBinary: Uint8Array, mid: MIDI, soundfont: SoundFont2, bankOffset?: number, encoding?: string, metadata?: RMIDMetadata): IndexedByteArray;
25
+ export function writeRMIDI(soundfontBinary: Uint8Array, mid: MIDI, soundfont: SoundFont2, bankOffset?: number, encoding?: string, metadata?: RMIDMetadata, correctBankOffset?: boolean): IndexedByteArray;
25
26
  export type RMIDINFOChunks = string;
26
27
  export namespace RMIDINFOChunks {
27
28
  let name: string;
@@ -53,10 +53,11 @@ export class BasicSoundFont {
53
53
  /**
54
54
  * Get the appropriate preset, undefined if not foun d
55
55
  * @param bankNr {number}
56
- * @param presetNr {number}
56
+ * @param programNr {number}
57
+ * @param fallbackToProgram {boolean} if true, if no exact match is found, will use any bank with the given preset
57
58
  * @return {BasicPreset}
58
59
  */
59
- getPresetNoFallback(bankNr: number, presetNr: number): BasicPreset;
60
+ getPresetNoFallback(bankNr: number, programNr: number, fallbackToProgram?: boolean): BasicPreset;
60
61
  /**
61
62
  * To avoid overlapping on multiple desfonts
62
63
  * @param offset {number}
@@ -65,10 +66,10 @@ export class BasicSoundFont {
65
66
  /**
66
67
  * Get the appropriate preset
67
68
  * @param bankNr {number}
68
- * @param presetNr {number}
69
+ * @param programNr {number}
69
70
  * @returns {BasicPreset}
70
71
  */
71
- getPreset(bankNr: number, presetNr: number): BasicPreset;
72
+ getPreset(bankNr: number, programNr: number): BasicPreset;
72
73
  /**
73
74
  * gets preset by name
74
75
  * @param presetName {string}
@@ -14,7 +14,7 @@
14
14
  * @property {number} NRPFine - the current fine value of the Non-Registered Parameter
15
15
  * @property {number} RPValue - the current value of the Registered Parameter
16
16
  *
17
- * @property {Preset} preset - the channel's preset
17
+ * @property {BasicPreset} preset - the channel's preset
18
18
  * @property {boolean} lockPreset - indicates whether the program on the channel is locked
19
19
  * @property {boolean} presetUsesOverride - indcates if the channel uses a preset from the override soundfont.
20
20
  *
@@ -104,7 +104,7 @@ export type WorkletProcessorChannel = {
104
104
  /**
105
105
  * - the channel's preset
106
106
  */
107
- preset: Preset;
107
+ preset: BasicPreset;
108
108
  /**
109
109
  * - indicates whether the program on the channel is locked
110
110
  */
@@ -117,6 +117,15 @@ class MIDI{
117
117
  this.midiName = readBytesAsString(this.rawMidiName, this.rawMidiName.length, undefined, false);
118
118
  nameDetected = true;
119
119
  }
120
+ // these can be used interchangeably
121
+ if(this.RMIDInfo['IALB'] && !this.RMIDInfo['IPRD'])
122
+ {
123
+ this.RMIDInfo['IPRD'] = this.RMIDInfo['IALB'];
124
+ }
125
+ if(this.RMIDInfo['PRD'] && !this.RMIDInfo['IALB'])
126
+ {
127
+ this.RMIDInfo['IALB'] = this.RMIDInfo['IPRD'];
128
+ }
120
129
  this.bankOffset = 1; // defaults to 1
121
130
  if(this.RMIDInfo[RMIDINFOChunks.bankOffset])
122
131
  {
@@ -52,9 +52,18 @@ const DEFAULT_COPYRIGHT = "Created using SpessaSynth";
52
52
  * @param bankOffset {number} the bank offset for RMIDI
53
53
  * @param encoding {string} the encoding of the RMIDI info chunk
54
54
  * @param metadata {RMIDMetadata} the metadata of the file. Optional. If provided, the encoding is forced to utf-8/
55
+ * @param correctBankOffset {boolean}
55
56
  * @returns {IndexedByteArray}
56
57
  */
57
- export function writeRMIDI(soundfontBinary, mid, soundfont, bankOffset = 0, encoding = "Shift_JIS", metadata = {})
58
+ export function writeRMIDI(
59
+ soundfontBinary,
60
+ mid,
61
+ soundfont,
62
+ bankOffset = 0,
63
+ encoding = "Shift_JIS",
64
+ metadata = {},
65
+ correctBankOffset = true
66
+ )
58
67
  {
59
68
  SpessaSynthGroup("%cWriting the RMIDI File...", consoleColors.info);
60
69
  SpessaSynthInfo(`%cConfiguration: Bank offset: %c${bankOffset}%c, encoding: %c${encoding}`,
@@ -64,271 +73,243 @@ export function writeRMIDI(soundfontBinary, mid, soundfont, bankOffset = 0, enco
64
73
  consoleColors.value);
65
74
  SpessaSynthInfo("metadata", metadata);
66
75
  SpessaSynthInfo("Initial bank offset", mid.bankOffset);
67
- // add offset to bank. See https://github.com/spessasus/sf2-rmidi-specification#readme
68
- // also fix presets that don't exists since midiplayer6 doesn't seem to default to 0 when nonextistent...
69
- let system = "gm";
70
- /**
71
- * The unwanted system messages such as gm/gm2 on
72
- * @type {{tNum: number, e: MidiMessage}[]}
73
- */
74
- let unwantedSystems = [];
75
- /**
76
- * indexes for tracks
77
- * @type {number[]}
78
- */
79
- const eventIndexes = Array(mid.tracks.length).fill(0);
80
- let remainingTracks = mid.tracks.length;
81
- function findFirstEventIndex()
82
- {
83
- let index = 0;
84
- let ticks = Infinity;
85
- mid.tracks.forEach((track, i) => {
86
- if(eventIndexes[i] >= track.length)
87
- {
88
- return;
89
- }
90
- if(track[eventIndexes[i]].ticks < ticks)
91
- {
92
- index = i;
93
- ticks = track[eventIndexes[i]].ticks;
94
- }
95
- });
96
- return index;
97
- }
98
- // it copies midiPorts everywhere else, but here 0 works so DO NOT CHANGE!!!!!!!
99
- const ports = Array(mid.tracks.length).fill(0);
100
- const channelsAmount = 16 + mid.midiPortChannelOffsets.reduce((max, cur) => cur > max ? cur: max);
101
- /**
102
- * @type {{
103
- * program: number,
104
- * drums: boolean,
105
- * lastBank: MidiMessage,
106
- * hasBankSelect: boolean
107
- * }[]}
108
- */
109
- const channelsInfo = [];
110
- for (let i = 0; i < channelsAmount; i++)
76
+ if(correctBankOffset)
111
77
  {
112
- channelsInfo.push({
113
- program: 0,
114
- drums: i % 16 === DEFAULT_PERCUSSION, // drums appear on 9 every 16 channels,
115
- lastBank: undefined,
116
- hasBankSelect: false,
117
- });
118
- }
119
- while(remainingTracks > 0)
120
- {
121
- let trackNum = findFirstEventIndex();
122
- const track = mid.tracks[trackNum];
123
- if(eventIndexes[trackNum] >= track.length)
124
- {
125
- remainingTracks--;
126
- continue;
127
- }
128
- const e = track[eventIndexes[trackNum]];
129
- eventIndexes[trackNum]++;
78
+ // add offset to bank.
79
+ // See https://github.com/spessasus/sf2-rmidi-specification#readme
80
+ // also fix presets that don't exists
81
+ // since midiplayer6 doesn't seem to default to 0 when nonextistent...
82
+ let system = "gm";
83
+ /**
84
+ * The unwanted system messages such as gm/gm2 on
85
+ * @type {{tNum: number, e: MidiMessage}[]}
86
+ */
87
+ let unwantedSystems = [];
88
+ /**
89
+ * indexes for tracks
90
+ * @type {number[]}
91
+ */
92
+ const eventIndexes = Array(mid.tracks.length).fill(0);
93
+ let remainingTracks = mid.tracks.length;
130
94
 
131
- let portOffset = mid.midiPortChannelOffsets[ports[trackNum]];
132
- if(e.messageStatusByte === messageTypes.midiPort)
133
- {
134
- ports[trackNum] = e.messageData[0];
135
- continue;
95
+ function findFirstEventIndex() {
96
+ let index = 0;
97
+ let ticks = Infinity;
98
+ mid.tracks.forEach((track, i) => {
99
+ if (eventIndexes[i] >= track.length) {
100
+ return;
101
+ }
102
+ if (track[eventIndexes[i]].ticks < ticks) {
103
+ index = i;
104
+ ticks = track[eventIndexes[i]].ticks;
105
+ }
106
+ });
107
+ return index;
136
108
  }
137
- const status = e.messageStatusByte & 0xF0;
138
- if(
139
- status !== messageTypes.controllerChange &&
140
- status !== messageTypes.programChange &&
141
- status !== messageTypes.systemExclusive
142
- )
143
- {
144
- continue
109
+
110
+ // it copies midiPorts everywhere else, but here 0 works so DO NOT CHANGE!!!!!!!
111
+ const ports = Array(mid.tracks.length).fill(0);
112
+ const channelsAmount = 16 + mid.midiPortChannelOffsets.reduce((max, cur) => cur > max ? cur : max);
113
+ /**
114
+ * @type {{
115
+ * program: number,
116
+ * drums: boolean,
117
+ * lastBank: MidiMessage,
118
+ * hasBankSelect: boolean
119
+ * }[]}
120
+ */
121
+ const channelsInfo = [];
122
+ for (let i = 0; i < channelsAmount; i++) {
123
+ channelsInfo.push({
124
+ program: 0,
125
+ drums: i % 16 === DEFAULT_PERCUSSION, // drums appear on 9 every 16 channels,
126
+ lastBank: undefined,
127
+ hasBankSelect: false,
128
+ });
145
129
  }
130
+ while (remainingTracks > 0) {
131
+ let trackNum = findFirstEventIndex();
132
+ const track = mid.tracks[trackNum];
133
+ if (eventIndexes[trackNum] >= track.length) {
134
+ remainingTracks--;
135
+ continue;
136
+ }
137
+ const e = track[eventIndexes[trackNum]];
138
+ eventIndexes[trackNum]++;
146
139
 
147
- if(status === messageTypes.systemExclusive)
148
- {
149
- // check for drum sysex
150
- if(
151
- e.messageData[0] !== 0x41 || // roland
152
- e.messageData[2] !== 0x42 || // GS
153
- e.messageData[3] !== 0x12 || // GS
154
- e.messageData[4] !== 0x40 || // system parameter
155
- (e.messageData[5] & 0x10 ) === 0 || // part parameter
156
- e.messageData[6] !== 0x15 // drum part
157
- )
158
- {
159
- // check for XG
160
- if(
161
- e.messageData[0] === 0x43 && // yamaha
162
- e.messageData[2] === 0x4C && // sXG ON
163
- e.messageData[5] === 0x7E &&
164
- e.messageData[6] === 0x00
165
- )
166
- {
167
- system = "xg";
168
- }
169
- else
170
- if(
171
- e.messageData[0] === 0x41 // roland
172
- && e.messageData[2] === 0x42 // GS
173
- && e.messageData[6] === 0x7F // Mode set
174
- )
175
- {
176
- system = "gs";
177
- }
178
- else
179
- if(
180
- e.messageData[0] === 0x7E // non realtime
181
- && e.messageData[2] === 0x09 // gm system
182
- )
183
- {
184
- system = "gm";
185
- unwantedSystems.push({
186
- tNum: trackNum,
187
- e: e
188
- });
189
- }
140
+ let portOffset = mid.midiPortChannelOffsets[ports[trackNum]];
141
+ if (e.messageStatusByte === messageTypes.midiPort) {
142
+ ports[trackNum] = e.messageData[0];
190
143
  continue;
191
144
  }
192
- const sysexChannel = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15][e.messageData[5] & 0x0F] + portOffset;
193
- channelsInfo[sysexChannel].drums = !!(e.messageData[7] > 0 && e.messageData[5] >> 4);
194
- continue;
195
- }
145
+ const status = e.messageStatusByte & 0xF0;
146
+ if (
147
+ status !== messageTypes.controllerChange &&
148
+ status !== messageTypes.programChange &&
149
+ status !== messageTypes.systemExclusive
150
+ ) {
151
+ continue
152
+ }
196
153
 
197
- // program change
198
- const chNum = (e.messageStatusByte & 0xF) + portOffset;
199
- const channel = channelsInfo[chNum];
200
- if(status === messageTypes.programChange)
201
- {
202
- // check if the preset for this program exists
203
- if(channel.drums)
204
- {
205
- if(soundfont.presets.findIndex(p => p.program === e.messageData[0] && p.bank === 128) === -1)
206
- {
207
- // doesn't exist. pick any preset that has the 128 bank.
208
- e.messageData[0] = soundfont.presets.find(p => p.bank === 128)?.program || 0;
154
+ if (status === messageTypes.systemExclusive) {
155
+ // check for drum sysex
156
+ if (
157
+ e.messageData[0] !== 0x41 || // roland
158
+ e.messageData[2] !== 0x42 || // GS
159
+ e.messageData[3] !== 0x12 || // GS
160
+ e.messageData[4] !== 0x40 || // system parameter
161
+ (e.messageData[5] & 0x10) === 0 || // part parameter
162
+ e.messageData[6] !== 0x15 // drum part
163
+ ) {
164
+ // check for XG
165
+ if (
166
+ e.messageData[0] === 0x43 && // yamaha
167
+ e.messageData[2] === 0x4C && // sXG ON
168
+ e.messageData[5] === 0x7E &&
169
+ e.messageData[6] === 0x00
170
+ ) {
171
+ system = "xg";
172
+ } else if (
173
+ e.messageData[0] === 0x41 // roland
174
+ && e.messageData[2] === 0x42 // GS
175
+ && e.messageData[6] === 0x7F // Mode set
176
+ ) {
177
+ system = "gs";
178
+ } else if (
179
+ e.messageData[0] === 0x7E // non realtime
180
+ && e.messageData[2] === 0x09 // gm system
181
+ ) {
182
+ system = "gm";
183
+ unwantedSystems.push({
184
+ tNum: trackNum,
185
+ e: e
186
+ });
187
+ }
188
+ continue;
209
189
  }
190
+ const sysexChannel = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15][e.messageData[5] & 0x0F] + portOffset;
191
+ channelsInfo[sysexChannel].drums = !!(e.messageData[7] > 0 && e.messageData[5] >> 4);
192
+ continue;
210
193
  }
211
- else
212
- {
213
- if (soundfont.presets.findIndex(p => p.program === e.messageData[0] && p.bank !== 128) === -1)
214
- {
215
- // doesn't exist. pick any preset that does not have the 128 bank.
216
- e.messageData[0] = soundfont.presets.find(p => p.bank !== 128)?.program || 0;
194
+
195
+ // program change
196
+ const chNum = (e.messageStatusByte & 0xF) + portOffset;
197
+ const channel = channelsInfo[chNum];
198
+ if (status === messageTypes.programChange) {
199
+ // check if the preset for this program exists
200
+ if (channel.drums) {
201
+ if (soundfont.presets.findIndex(p => p.program === e.messageData[0] && p.bank === 128) === -1) {
202
+ // doesn't exist. pick any preset that has the 128 bank.
203
+ e.messageData[0] = soundfont.presets.find(p => p.bank === 128)?.program || 0;
204
+ }
205
+ } else {
206
+ if (soundfont.presets.findIndex(p => p.program === e.messageData[0] && p.bank !== 128) === -1) {
207
+ // doesn't exist. pick any preset that does not have the 128 bank.
208
+ e.messageData[0] = soundfont.presets.find(p => p.bank !== 128)?.program || 0;
209
+ }
210
+ }
211
+ channel.program = e.messageData[0];
212
+ // check if this preset exists for program and bank
213
+ const realBank = Math.max(0, channel.lastBank?.messageData[1] - mid.bankOffset); // make sure to take the previous bank offset into account
214
+ const bank = channel.drums ? 128 : realBank;
215
+ if (channel.lastBank === undefined) {
216
+ continue;
217
+ }
218
+ if (system === "xg" && channel.drums) {
219
+ // drums override: set bank to 127
220
+ channelsInfo[chNum].lastBank.messageData[1] = 127;
221
+ }
222
+
223
+ if (soundfont.presets.findIndex(p => p.bank === bank && p.program === e.messageData[0]) === -1) {
224
+ // no preset with this bank. find this program with any bank
225
+ const targetBank = (soundfont.presets.find(p => p.program === e.messageData[0])?.bank + bankOffset) || bankOffset;
226
+ channel.lastBank.messageData[1] = targetBank;
227
+ SpessaSynthInfo(`%cNo preset %c${bank}:${e.messageData[0]}%c. Changing bank to ${targetBank}.`,
228
+ consoleColors.info,
229
+ consoleColors.recognized,
230
+ consoleColors.info);
231
+ } else {
232
+ // there is a preset with this bank. add offset. For drums add the normal offset.
233
+ const newBank = (bank === 128 ? 0 : realBank) + bankOffset;
234
+ channel.lastBank.messageData[1] = newBank;
235
+ SpessaSynthInfo(`%cPreset %c${bank}:${e.messageData[0]}%c exists. Changing bank to ${newBank}.`,
236
+ consoleColors.info,
237
+ consoleColors.recognized,
238
+ consoleColors.info);
217
239
  }
218
- }
219
- channel.program = e.messageData[0];
220
- // check if this preset exists for program and bank
221
- const realBank = Math.max(0,channel.lastBank?.messageData[1] - mid.bankOffset); // make sure to take the previous bank offset into account
222
- const bank = channel.drums ? 128 : realBank;
223
- if(channel.lastBank === undefined)
224
- {
225
240
  continue;
226
241
  }
227
- if(system === "xg" && channel.drums)
228
- {
229
- // drums override: set bank to 127
230
- channelsInfo[chNum].lastBank.messageData[1] = 127;
231
- }
232
-
233
- if(soundfont.presets.findIndex(p => p.bank === bank && p.program === e.messageData[0]) === -1)
234
- {
235
- // no preset with this bank. find this program with any bank
236
- const targetBank = (soundfont.presets.find(p => p.program === e.messageData[0])?.bank + bankOffset) || bankOffset;
237
- channel.lastBank.messageData[1] = targetBank;
238
- SpessaSynthInfo(`%cNo preset %c${bank}:${e.messageData[0]}%c. Changing bank to ${targetBank}.`,
239
- consoleColors.info,
240
- consoleColors.recognized,
241
- consoleColors.info);
242
+ // we only care about bank select
243
+ if (e.messageData[0] !== midiControllers.bankSelect) {
244
+ continue;
242
245
  }
243
- else
244
- {
245
- // there is a preset with this bank. add offset. For drums add the normal offset.
246
- const newBank = (bank === 128 ? 0 : realBank) + bankOffset;
247
- channel.lastBank.messageData[1] = newBank;
248
- SpessaSynthInfo(`%cPreset %c${bank}:${e.messageData[0]}%c exists. Changing bank to ${newBank}.`,
249
- consoleColors.info,
250
- consoleColors.recognized,
251
- consoleColors.info);
246
+ // bank select
247
+ channel.hasBankSelect = true;
248
+ if (system === "xg") {
249
+ // check for xg drums
250
+ channel.drums = e.messageData[1] === 120 || e.messageData[1] === 126 || e.messageData[1] === 127;
252
251
  }
253
- continue;
252
+ channel.lastBank = e;
254
253
  }
255
- // we only care about bank select
256
- if(e.messageData[0] !== midiControllers.bankSelect)
257
- {
258
- continue;
259
- }
260
- // bank select
261
- channel.hasBankSelect = true;
262
- if(system === "xg")
263
- {
264
- // check for xg drums
265
- channel.drums = e.messageData[1] === 120 || e.messageData[1] === 126 || e.messageData[1] === 127;
266
- }
267
- channel.lastBank = e;
268
- }
269
254
 
270
- // add missing bank selects
271
- // add all bank selects that are missing for this track
272
- channelsInfo.forEach((has, ch) => {
273
- if(has.hasBankSelect === true)
274
- {
275
- return;
276
- }
277
- // find first program change (for the given channel)
278
- const midiChannel = ch % 16;
279
- const status = messageTypes.programChange | midiChannel;
280
- // find track with this channel being used
281
- const portOffset = Math.floor(ch / 16) * 16;
282
- const port = mid.midiPortChannelOffsets.indexOf(portOffset);
283
- const track = mid.tracks.find((t, tNum) => mid.midiPorts[tNum] === port && mid.usedChannelsOnTrack[tNum].has(midiChannel));
284
- if(track === undefined)
285
- {
286
- // this channel is not used at all
287
- return;
288
- }
289
- let indexToAdd = track.findIndex(e => e.messageStatusByte === status);
290
- if(indexToAdd === -1)
291
- {
292
- // no program change...
293
- // add programs if they are missing from the track (need them to activate bank 1 for the embedded sfont)
294
- const programIndex = track.findIndex(e => (e.messageStatusByte > 0x80 && e.messageStatusByte < 0xF0) && (e.messageStatusByte & 0xF) === midiChannel);
295
- if(programIndex === -1)
296
- {
297
- // no voices??? skip
255
+ // add missing bank selects
256
+ // add all bank selects that are missing for this track
257
+ channelsInfo.forEach((has, ch) => {
258
+ if (has.hasBankSelect === true) {
259
+ return;
260
+ }
261
+ // find first program change (for the given channel)
262
+ const midiChannel = ch % 16;
263
+ const status = messageTypes.programChange | midiChannel;
264
+ // find track with this channel being used
265
+ const portOffset = Math.floor(ch / 16) * 16;
266
+ const port = mid.midiPortChannelOffsets.indexOf(portOffset);
267
+ const track = mid.tracks.find((t, tNum) => mid.midiPorts[tNum] === port && mid.usedChannelsOnTrack[tNum].has(midiChannel));
268
+ if (track === undefined) {
269
+ // this channel is not used at all
298
270
  return;
299
271
  }
300
- const programTicks = track[programIndex].ticks;
301
- const targetProgram = soundfont.getPreset(0, 0).program;
302
- track.splice(programIndex, 0, new MidiMessage(
303
- programTicks,
304
- messageTypes.programChange | midiChannel,
305
- new IndexedByteArray([targetProgram])
272
+ let indexToAdd = track.findIndex(e => e.messageStatusByte === status);
273
+ if (indexToAdd === -1) {
274
+ // no program change...
275
+ // add programs if they are missing from the track
276
+ // (need them to activate bank 1 for the embedded sfont)
277
+ const programIndex = track.findIndex(e => (e.messageStatusByte > 0x80 && e.messageStatusByte < 0xF0) && (e.messageStatusByte & 0xF) === midiChannel);
278
+ if (programIndex === -1) {
279
+ // no voices??? skip
280
+ return;
281
+ }
282
+ const programTicks = track[programIndex].ticks;
283
+ const targetProgram = soundfont.getPreset(0, 0).program;
284
+ track.splice(programIndex, 0, new MidiMessage(
285
+ programTicks,
286
+ messageTypes.programChange | midiChannel,
287
+ new IndexedByteArray([targetProgram])
288
+ ));
289
+ indexToAdd = programIndex;
290
+ }
291
+ SpessaSynthInfo(`%cAdding bank select for %c${ch}`,
292
+ consoleColors.info,
293
+ consoleColors.recognized)
294
+ const ticks = track[indexToAdd].ticks;
295
+ const targetBank = (soundfont.getPreset(0, has.program)?.bank + bankOffset) || bankOffset;
296
+ track.splice(indexToAdd, 0, new MidiMessage(
297
+ ticks,
298
+ messageTypes.controllerChange | midiChannel,
299
+ new IndexedByteArray([midiControllers.bankSelect, targetBank])
306
300
  ));
307
- indexToAdd = programIndex;
308
- }
309
- SpessaSynthInfo(`%cAdding bank select for %c${ch}`,
310
- consoleColors.info,
311
- consoleColors.recognized)
312
- const ticks = track[indexToAdd].ticks;
313
- const targetBank = (soundfont.getPreset(0, has.program)?.bank + bankOffset) || bankOffset;
314
- track.splice(indexToAdd,0, new MidiMessage(
315
- ticks,
316
- messageTypes.controllerChange | midiChannel,
317
- new IndexedByteArray([midiControllers.bankSelect, targetBank])
318
- ));
319
- });
301
+ });
320
302
 
321
- // make sure to put xg if gm
322
- if(system !== "gs" && system !== "xg")
323
- {
324
- for(const m of unwantedSystems)
325
- {
326
- mid.tracks[m.tNum].splice(mid.tracks[m.tNum].indexOf(m.e), 1);
327
- }
328
- let index = 0;
329
- if(mid.tracks[0][0].messageStatusByte === messageTypes.trackName)
330
- index++;
303
+ // make sure to put xg if gm
304
+ if (system !== "gs" && system !== "xg") {
305
+ for (const m of unwantedSystems) {
306
+ mid.tracks[m.tNum].splice(mid.tracks[m.tNum].indexOf(m.e), 1);
307
+ }
308
+ let index = 0;
309
+ if (mid.tracks[0][0].messageStatusByte === messageTypes.trackName)
310
+ index++;
331
311
  mid.tracks[0].splice(index, 0, getGsOn(0));
312
+ }
332
313
  }
333
314
  const newMid = new IndexedByteArray(writeMIDIFile(mid).buffer);
334
315
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spessasynth_lib",
3
- "version": "3.16.4",
3
+ "version": "3.16.5",
4
4
  "description": "No compromise MIDI and SoundFont2 Synthesizer library",
5
5
  "browser": "index.js",
6
6
  "types": "@types/index.d.ts",