spessasynth_core 3.26.5 → 3.26.7
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.
- package/README.md +10 -8
- package/package.json +1 -1
- package/src/midi/basic_midi.js +4 -1
- package/src/soundfont/basic_soundfont/generator.js +9 -1
- package/src/synthetizer/audio_engine/engine_components/controller_tables.js +6 -5
- package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +95 -0
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +11 -10
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +2 -2
- package/src/synthetizer/audio_engine/engine_components/voice.js +6 -2
- package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +2 -1
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +20 -21
- package/src/synthetizer/audio_engine/engine_methods/note_on.js +28 -8
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +18 -11
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +3 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +2 -1
- package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +442 -173
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +1 -0
- package/src/synthetizer/audio_engine/main_processor.js +11 -0
|
@@ -6,6 +6,9 @@ import { isSystemXG } from "../../../utils/xg_hacks.js";
|
|
|
6
6
|
import { masterParameterType } from "./controller_control/master_parameters.js";
|
|
7
7
|
import { readBytesAsString } from "../../../utils/byte_functions/string.js";
|
|
8
8
|
import { synthDisplayTypes } from "../engine_components/enums.js";
|
|
9
|
+
import { customControllers, NON_CC_INDEX_OFFSET } from "../engine_components/controller_tables.js";
|
|
10
|
+
import { modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
|
|
11
|
+
import { generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* KeyNum: tuning
|
|
@@ -40,29 +43,54 @@ function getTuning(byte1, byte2, byte3)
|
|
|
40
43
|
return { midiNote: midiNote, centTuning: fraction * 0.0061 };
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
|
|
44
46
|
/**
|
|
45
47
|
* Executes a system exclusive
|
|
46
|
-
* @param
|
|
48
|
+
* @param syx {number[]|IndexedByteArray} - the message data without f0
|
|
47
49
|
* @param channelOffset {number}
|
|
48
50
|
* @this {SpessaSynthProcessor}
|
|
49
51
|
*/
|
|
50
|
-
export function systemExclusive(
|
|
52
|
+
export function systemExclusive(syx, channelOffset = 0)
|
|
51
53
|
{
|
|
52
|
-
const type =
|
|
53
|
-
if (this.deviceID !== ALL_CHANNELS_OR_DIFFERENT_ACTION &&
|
|
54
|
+
const type = syx[0];
|
|
55
|
+
if (this.deviceID !== ALL_CHANNELS_OR_DIFFERENT_ACTION && syx[1] !== 0x7F)
|
|
54
56
|
{
|
|
55
|
-
if (this.deviceID !==
|
|
57
|
+
if (this.deviceID !== syx[1])
|
|
56
58
|
{
|
|
57
59
|
// not our device ID
|
|
58
60
|
return;
|
|
59
61
|
}
|
|
60
62
|
}
|
|
63
|
+
|
|
64
|
+
function niceLogging(channel, value, what, units)
|
|
65
|
+
{
|
|
66
|
+
SpessaSynthInfo(
|
|
67
|
+
`%cChannel %c${channel}%c ${what}. %c${value} ${units}%c, with %c${arrayToHexString(syx)}`,
|
|
68
|
+
consoleColors.info,
|
|
69
|
+
consoleColors.recognized,
|
|
70
|
+
consoleColors.info,
|
|
71
|
+
consoleColors.value,
|
|
72
|
+
consoleColors.info,
|
|
73
|
+
consoleColors.value
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function notRecognized()
|
|
78
|
+
{
|
|
79
|
+
// this is some other GS sysex...
|
|
80
|
+
SpessaSynthWarn(
|
|
81
|
+
`%cUnrecognized Roland %cGS %cSysEx: %c${arrayToHexString(syx)}`,
|
|
82
|
+
consoleColors.warn,
|
|
83
|
+
consoleColors.recognized,
|
|
84
|
+
consoleColors.warn,
|
|
85
|
+
consoleColors.unrecognized
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
61
89
|
switch (type)
|
|
62
90
|
{
|
|
63
91
|
default:
|
|
64
92
|
SpessaSynthWarn(
|
|
65
|
-
`%cUnrecognized SysEx: %c${arrayToHexString(
|
|
93
|
+
`%cUnrecognized SysEx: %c${arrayToHexString(syx)}`,
|
|
66
94
|
consoleColors.warn,
|
|
67
95
|
consoleColors.unrecognized
|
|
68
96
|
);
|
|
@@ -71,16 +99,16 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
71
99
|
// non realtime
|
|
72
100
|
case 0x7E:
|
|
73
101
|
case 0x7F:
|
|
74
|
-
switch (
|
|
102
|
+
switch (syx[2])
|
|
75
103
|
{
|
|
76
104
|
case 0x04:
|
|
77
105
|
let cents;
|
|
78
106
|
// device control
|
|
79
|
-
switch (
|
|
107
|
+
switch (syx[3])
|
|
80
108
|
{
|
|
81
109
|
case 0x01:
|
|
82
110
|
// main volume
|
|
83
|
-
const vol =
|
|
111
|
+
const vol = syx[5] << 7 | syx[4];
|
|
84
112
|
this.setMIDIVolume(vol / 16384);
|
|
85
113
|
SpessaSynthInfo(
|
|
86
114
|
`%cMaster Volume. Volume: %c${vol}`,
|
|
@@ -92,7 +120,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
92
120
|
case 0x02:
|
|
93
121
|
// main balance
|
|
94
122
|
// midi spec page 62
|
|
95
|
-
const balance =
|
|
123
|
+
const balance = syx[5] << 7 | syx[4];
|
|
96
124
|
const pan = (balance - 8192) / 8192;
|
|
97
125
|
this.setMasterParameter(masterParameterType.masterPan, pan);
|
|
98
126
|
SpessaSynthInfo(
|
|
@@ -105,7 +133,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
105
133
|
|
|
106
134
|
case 0x03:
|
|
107
135
|
// fine-tuning
|
|
108
|
-
const tuningValue = ((
|
|
136
|
+
const tuningValue = ((syx[5] << 7) | syx[6]) - 8192;
|
|
109
137
|
cents = Math.floor(tuningValue / 81.92); // [-100;+99] cents range
|
|
110
138
|
this.setMasterTuning(cents);
|
|
111
139
|
SpessaSynthInfo(
|
|
@@ -118,7 +146,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
118
146
|
case 0x04:
|
|
119
147
|
// coarse tuning
|
|
120
148
|
// lsb is ignored
|
|
121
|
-
const semitones =
|
|
149
|
+
const semitones = syx[5] - 64;
|
|
122
150
|
cents = semitones * 100;
|
|
123
151
|
this.setMasterTuning(cents);
|
|
124
152
|
SpessaSynthInfo(
|
|
@@ -130,7 +158,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
130
158
|
|
|
131
159
|
default:
|
|
132
160
|
SpessaSynthWarn(
|
|
133
|
-
`%cUnrecognized MIDI Device Control Real-time message: %c${arrayToHexString(
|
|
161
|
+
`%cUnrecognized MIDI Device Control Real-time message: %c${arrayToHexString(syx)}`,
|
|
134
162
|
consoleColors.warn,
|
|
135
163
|
consoleColors.unrecognized
|
|
136
164
|
);
|
|
@@ -139,12 +167,12 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
139
167
|
|
|
140
168
|
case 0x09:
|
|
141
169
|
// gm system related
|
|
142
|
-
if (
|
|
170
|
+
if (syx[3] === 0x01)
|
|
143
171
|
{
|
|
144
172
|
SpessaSynthInfo("%cGM1 system on", consoleColors.info);
|
|
145
173
|
this.setSystem("gm");
|
|
146
174
|
}
|
|
147
|
-
else if (
|
|
175
|
+
else if (syx[3] === 0x03)
|
|
148
176
|
{
|
|
149
177
|
SpessaSynthInfo("%cGM2 system on", consoleColors.info);
|
|
150
178
|
this.setSystem("gm2");
|
|
@@ -160,18 +188,18 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
160
188
|
// https://midi.org/midi-tuning-updated-specification
|
|
161
189
|
case 0x08:
|
|
162
190
|
let currentMessageIndex = 4;
|
|
163
|
-
switch (
|
|
191
|
+
switch (syx[3])
|
|
164
192
|
{
|
|
165
193
|
// bulk tuning dump: all 128 notes
|
|
166
194
|
case 0x01:
|
|
167
|
-
const program =
|
|
195
|
+
const program = syx[currentMessageIndex++];
|
|
168
196
|
// read the name
|
|
169
|
-
|
|
170
|
-
const tuningName = readBytesAsString(
|
|
197
|
+
syx.currentIndex = currentMessageIndex;
|
|
198
|
+
const tuningName = readBytesAsString(syx, 16);
|
|
171
199
|
currentMessageIndex += 16;
|
|
172
|
-
if (
|
|
200
|
+
if (syx.length < 384)
|
|
173
201
|
{
|
|
174
|
-
SpessaSynthWarn(`The Bulk Tuning Dump is too short! (${
|
|
202
|
+
SpessaSynthWarn(`The Bulk Tuning Dump is too short! (${syx.length} bytes, at least 384 are expected)`);
|
|
175
203
|
return;
|
|
176
204
|
}
|
|
177
205
|
// 128 frequencies follow
|
|
@@ -179,9 +207,9 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
179
207
|
{
|
|
180
208
|
// set the given tuning to the program
|
|
181
209
|
this.tunings[program][i] = getTuning(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
210
|
+
syx[currentMessageIndex++],
|
|
211
|
+
syx[currentMessageIndex++],
|
|
212
|
+
syx[currentMessageIndex++]
|
|
185
213
|
);
|
|
186
214
|
}
|
|
187
215
|
SpessaSynthInfo(
|
|
@@ -197,21 +225,21 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
197
225
|
// single note change bank
|
|
198
226
|
case 0x02:
|
|
199
227
|
case 0x07:
|
|
200
|
-
if (
|
|
228
|
+
if (syx[3] === 0x07)
|
|
201
229
|
{
|
|
202
230
|
// skip the bank
|
|
203
231
|
currentMessageIndex++;
|
|
204
232
|
}
|
|
205
233
|
// get program and number of changes
|
|
206
|
-
const tuningProgram =
|
|
207
|
-
const numberOfChanges =
|
|
234
|
+
const tuningProgram = syx[currentMessageIndex++];
|
|
235
|
+
const numberOfChanges = syx[currentMessageIndex++];
|
|
208
236
|
for (let i = 0; i < numberOfChanges; i++)
|
|
209
237
|
{
|
|
210
238
|
// set the given tuning to the program
|
|
211
|
-
this.tunings[tuningProgram][
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
239
|
+
this.tunings[tuningProgram][syx[currentMessageIndex++]] = getTuning(
|
|
240
|
+
syx[currentMessageIndex++],
|
|
241
|
+
syx[currentMessageIndex++],
|
|
242
|
+
syx[currentMessageIndex++]
|
|
215
243
|
);
|
|
216
244
|
}
|
|
217
245
|
SpessaSynthInfo(
|
|
@@ -230,12 +258,12 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
230
258
|
// get tuning:
|
|
231
259
|
const newOctaveTuning = new Int8Array(12);
|
|
232
260
|
// start from bit 7
|
|
233
|
-
if (
|
|
261
|
+
if (syx[3] === 0x08)
|
|
234
262
|
{
|
|
235
263
|
// 1 byte tuning: 0 is -64 cents, 64 is 0, 127 is +63
|
|
236
264
|
for (let i = 0; i < 12; i++)
|
|
237
265
|
{
|
|
238
|
-
newOctaveTuning[i] =
|
|
266
|
+
newOctaveTuning[i] = syx[7 + i] - 64;
|
|
239
267
|
}
|
|
240
268
|
}
|
|
241
269
|
else
|
|
@@ -243,17 +271,17 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
243
271
|
// 2 byte tuning. Like fine tune: 0 is -100 cents, 8192 is 0 cents, 16,383 is +100 cents
|
|
244
272
|
for (let i = 0; i < 24; i += 2)
|
|
245
273
|
{
|
|
246
|
-
const tuning = ((
|
|
274
|
+
const tuning = ((syx[7 + i] << 7) | syx[8 + i]) - 8192;
|
|
247
275
|
newOctaveTuning[i / 2] = Math.floor(tuning / 81.92); // map to [-100;+99] cents
|
|
248
276
|
}
|
|
249
277
|
}
|
|
250
278
|
// apply to channels (ordered from 0)
|
|
251
279
|
// bit 1: 14 and 15
|
|
252
|
-
if ((
|
|
280
|
+
if ((syx[4] & 1) === 1)
|
|
253
281
|
{
|
|
254
282
|
this.midiAudioChannels[14 + channelOffset].setOctaveTuning(newOctaveTuning);
|
|
255
283
|
}
|
|
256
|
-
if (((
|
|
284
|
+
if (((syx[4] >> 1) & 1) === 1)
|
|
257
285
|
{
|
|
258
286
|
this.midiAudioChannels[15 + channelOffset].setOctaveTuning(newOctaveTuning);
|
|
259
287
|
}
|
|
@@ -261,7 +289,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
261
289
|
// bit 2: channels 7 to 13
|
|
262
290
|
for (let i = 0; i < 7; i++)
|
|
263
291
|
{
|
|
264
|
-
const bit = (
|
|
292
|
+
const bit = (syx[5] >> i) & 1;
|
|
265
293
|
if (bit === 1)
|
|
266
294
|
{
|
|
267
295
|
this.midiAudioChannels[7 + i + channelOffset].setOctaveTuning(newOctaveTuning);
|
|
@@ -271,7 +299,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
271
299
|
// bit 3: channels 0 to 16
|
|
272
300
|
for (let i = 0; i < 7; i++)
|
|
273
301
|
{
|
|
274
|
-
const bit = (
|
|
302
|
+
const bit = (syx[6] >> i) & 1;
|
|
275
303
|
if (bit === 1)
|
|
276
304
|
{
|
|
277
305
|
this.midiAudioChannels[i + channelOffset].setOctaveTuning(newOctaveTuning);
|
|
@@ -280,7 +308,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
280
308
|
|
|
281
309
|
SpessaSynthInfo(
|
|
282
310
|
`%cMIDI Octave Scale ${
|
|
283
|
-
|
|
311
|
+
syx[3] === 0x08 ? "(1 byte)" : "(2 bytes)"
|
|
284
312
|
} tuning via Tuning: %c${newOctaveTuning.join(" ")}`,
|
|
285
313
|
consoleColors.info,
|
|
286
314
|
consoleColors.value
|
|
@@ -289,7 +317,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
289
317
|
|
|
290
318
|
default:
|
|
291
319
|
SpessaSynthWarn(
|
|
292
|
-
`%cUnrecognized MIDI Tuning standard message: %c${arrayToHexString(
|
|
320
|
+
`%cUnrecognized MIDI Tuning standard message: %c${arrayToHexString(syx)}`,
|
|
293
321
|
consoleColors.warn,
|
|
294
322
|
consoleColors.unrecognized
|
|
295
323
|
);
|
|
@@ -299,7 +327,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
299
327
|
|
|
300
328
|
default:
|
|
301
329
|
SpessaSynthWarn(
|
|
302
|
-
`%cUnrecognized MIDI Realtime/non realtime message: %c${arrayToHexString(
|
|
330
|
+
`%cUnrecognized MIDI Realtime/non realtime message: %c${arrayToHexString(syx)}`,
|
|
303
331
|
consoleColors.warn,
|
|
304
332
|
consoleColors.unrecognized
|
|
305
333
|
);
|
|
@@ -311,54 +339,24 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
311
339
|
// http://www.bandtrax.com.au/sysex.htm
|
|
312
340
|
// https://cdn.roland.com/assets/media/pdf/AT-20R_30R_MI.pdf
|
|
313
341
|
case 0x41:
|
|
314
|
-
|
|
315
|
-
function notRecognized()
|
|
316
|
-
{
|
|
317
|
-
// this is some other GS sysex...
|
|
318
|
-
SpessaSynthWarn(
|
|
319
|
-
`%cUnrecognized Roland %cGS %cSysEx: %c${arrayToHexString(messageData)}`,
|
|
320
|
-
consoleColors.warn,
|
|
321
|
-
consoleColors.recognized,
|
|
322
|
-
consoleColors.warn,
|
|
323
|
-
consoleColors.unrecognized
|
|
324
|
-
);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
if (messageData[2] === 0x42 && messageData[3] === 0x12)
|
|
342
|
+
if (syx[2] === 0x42 && syx[3] === 0x12)
|
|
328
343
|
{
|
|
329
344
|
// this is a GS sysex
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
// GS mode set
|
|
335
|
-
if (messageValue === 0x00)
|
|
336
|
-
{
|
|
337
|
-
// this is a GS reset
|
|
338
|
-
SpessaSynthInfo("%cGS Reset received!", consoleColors.info);
|
|
339
|
-
this.resetAllControllers(false);
|
|
340
|
-
this.setSystem("gs");
|
|
341
|
-
}
|
|
342
|
-
else if (messageValue === 0x7F)
|
|
343
|
-
{
|
|
344
|
-
// GS mode off
|
|
345
|
-
SpessaSynthInfo("%cGS system off, switching to GM2", consoleColors.info);
|
|
346
|
-
this.resetAllControllers(false);
|
|
347
|
-
this.setSystem("gm2");
|
|
348
|
-
}
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
else if (messageData[4] === 0x40)
|
|
345
|
+
const messageValue = syx[7];
|
|
346
|
+
// syx[5] and [6] is the system parameter, syx[7] is the value
|
|
347
|
+
// either patch common or SC-88 mode set
|
|
348
|
+
if (syx[4] === 0x40 || (syx[4] === 0x00 && syx[6] === 0x7F))
|
|
352
349
|
{
|
|
353
|
-
// this is a
|
|
354
|
-
if ((
|
|
350
|
+
// this is a channel parameter
|
|
351
|
+
if ((syx[5] & 0x10) > 0)
|
|
355
352
|
{
|
|
356
353
|
// this is an individual part (channel) parameter
|
|
357
354
|
// determine the channel 0 means channel 10 (default), 1 means 1 etc.
|
|
358
|
-
|
|
355
|
+
// SC88 manual page 196
|
|
356
|
+
const channel = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15][syx[5] & 0x0F] + channelOffset;
|
|
359
357
|
// for example, 0x1A means A = 11, which corresponds to channel 12 (counting from 1)
|
|
360
358
|
const channelObject = this.midiAudioChannels[channel];
|
|
361
|
-
switch (
|
|
359
|
+
switch (syx[6])
|
|
362
360
|
{
|
|
363
361
|
default:
|
|
364
362
|
// this is some other GS sysex...
|
|
@@ -367,14 +365,14 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
367
365
|
|
|
368
366
|
case 0x15:
|
|
369
367
|
// this is the Use for Drum Part sysex (multiple drums)
|
|
370
|
-
const isDrums = messageValue > 0 &&
|
|
368
|
+
const isDrums = messageValue > 0 && syx[5] >> 4; // if set to other than 0, is a drum channel
|
|
371
369
|
channelObject.setDrums(isDrums);
|
|
372
370
|
SpessaSynthInfo(
|
|
373
371
|
`%cChannel %c${channel}%c ${isDrums ?
|
|
374
372
|
"is now a drum channel"
|
|
375
373
|
:
|
|
376
374
|
"now isn't a drum channel"
|
|
377
|
-
}%c via: %c${arrayToHexString(
|
|
375
|
+
}%c via: %c${arrayToHexString(syx)}`,
|
|
378
376
|
consoleColors.info,
|
|
379
377
|
consoleColors.value,
|
|
380
378
|
consoleColors.recognized,
|
|
@@ -386,17 +384,8 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
386
384
|
case 0x16:
|
|
387
385
|
// this is the pitch key shift sysex
|
|
388
386
|
const keyShift = messageValue - 64;
|
|
389
|
-
channelObject.
|
|
390
|
-
|
|
391
|
-
`%cChannel %c${channel}%c pitch shift. Semitones %c${keyShift}%c, with %c${arrayToHexString(
|
|
392
|
-
messageData)}`,
|
|
393
|
-
consoleColors.info,
|
|
394
|
-
consoleColors.recognized,
|
|
395
|
-
consoleColors.info,
|
|
396
|
-
consoleColors.value,
|
|
397
|
-
consoleColors.info,
|
|
398
|
-
consoleColors.value
|
|
399
|
-
);
|
|
387
|
+
channelObject.setCustomController(customControllers.channelKeyShift, keyShift);
|
|
388
|
+
niceLogging(channel, keyShift, "key shift", "keys");
|
|
400
389
|
return;
|
|
401
390
|
|
|
402
391
|
// pan position
|
|
@@ -444,96 +433,376 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
444
433
|
case 0x4A:
|
|
445
434
|
case 0x4B:
|
|
446
435
|
// scale tuning: up to 12 bytes
|
|
447
|
-
const tuningBytes =
|
|
436
|
+
const tuningBytes = syx.length - 9; // data starts at 7, minus checksum and f7
|
|
448
437
|
// read em bytes
|
|
449
438
|
const newTuning = new Int8Array(12);
|
|
450
439
|
for (let i = 0; i < tuningBytes; i++)
|
|
451
440
|
{
|
|
452
|
-
newTuning[i] =
|
|
441
|
+
newTuning[i] = syx[i + 7] - 64;
|
|
453
442
|
}
|
|
454
443
|
channelObject.setOctaveTuning(newTuning);
|
|
455
444
|
const cents = messageValue - 64;
|
|
456
|
-
|
|
457
|
-
`%cChannel %c${channel}%c octave scale tuning. Cents %c${newTuning.join(
|
|
458
|
-
" ")}%c, with %c${arrayToHexString(messageData)}`,
|
|
459
|
-
consoleColors.info,
|
|
460
|
-
consoleColors.recognized,
|
|
461
|
-
consoleColors.info,
|
|
462
|
-
consoleColors.value,
|
|
463
|
-
consoleColors.info,
|
|
464
|
-
consoleColors.value
|
|
465
|
-
);
|
|
445
|
+
niceLogging(channel, newTuning.join(" "), "octave scale tuning", "cents");
|
|
466
446
|
channelObject.setTuning(cents);
|
|
467
447
|
break;
|
|
468
448
|
}
|
|
469
449
|
return;
|
|
470
450
|
}
|
|
471
451
|
else
|
|
472
|
-
// this is a
|
|
473
|
-
if (
|
|
452
|
+
// this is a channel parameter also
|
|
453
|
+
if ((syx[5] & 0x20) > 0)
|
|
474
454
|
{
|
|
475
|
-
//
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
455
|
+
// this is an individual part (channel) parameter
|
|
456
|
+
// determine the channel 0 means channel 10 (default), 1 means 1 etc.
|
|
457
|
+
const channel = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15][syx[5] & 0x0F] + channelOffset;
|
|
458
|
+
// for example, 0x1A means A = 11, which corresponds to channel 12 (counting from 1)
|
|
459
|
+
const channelObject = this.midiAudioChannels[channel];
|
|
460
|
+
const centeredValue = (messageValue - 64);
|
|
461
|
+
const normalizedValue = centeredValue / 64;
|
|
462
|
+
const normalizedNotCentered = messageValue / 128;
|
|
463
|
+
|
|
464
|
+
// setup receivers for cc to parameter (sc-88 manual page 198)
|
|
465
|
+
const setupReceivers = (source, sourceName, bipolar = false) =>
|
|
466
|
+
{
|
|
467
|
+
switch (syx[6] & 0x0F)
|
|
468
|
+
{
|
|
469
|
+
case 0x00:
|
|
470
|
+
// see https://github.com/spessasus/SpessaSynth/issues/154
|
|
471
|
+
// pitch control
|
|
472
|
+
channelObject.sysExModulators.setModulator(
|
|
473
|
+
source,
|
|
474
|
+
generatorTypes.fineTune,
|
|
475
|
+
centeredValue * 100,
|
|
476
|
+
bipolar
|
|
477
|
+
);
|
|
478
|
+
niceLogging(channel, centeredValue, `${sourceName} pitch control`, "semitones");
|
|
479
|
+
break;
|
|
480
|
+
|
|
481
|
+
case 0x01:
|
|
482
|
+
// cutoff
|
|
483
|
+
channelObject.sysExModulators.setModulator(
|
|
484
|
+
source,
|
|
485
|
+
generatorTypes.initialFilterFc,
|
|
486
|
+
normalizedValue * 9600,
|
|
487
|
+
bipolar
|
|
488
|
+
);
|
|
489
|
+
niceLogging(
|
|
490
|
+
channel,
|
|
491
|
+
normalizedValue * 9600,
|
|
492
|
+
`${sourceName} pitch control`,
|
|
493
|
+
"cents"
|
|
494
|
+
);
|
|
495
|
+
break;
|
|
496
|
+
|
|
497
|
+
case 0x02:
|
|
498
|
+
// amplitude
|
|
499
|
+
channelObject.sysExModulators.setModulator(
|
|
500
|
+
source,
|
|
501
|
+
generatorTypes.initialAttenuation,
|
|
502
|
+
normalizedValue * 960, // spec says "100%" so 960cB in sf2
|
|
503
|
+
bipolar
|
|
504
|
+
);
|
|
505
|
+
niceLogging(channel, normalizedValue * 960, `${sourceName} amplitude`, "cB");
|
|
506
|
+
break;
|
|
507
|
+
|
|
508
|
+
// rate control is ignored as it is in hertz
|
|
509
|
+
|
|
510
|
+
case 0x04:
|
|
511
|
+
// LFO1 pitch depth
|
|
512
|
+
channelObject.sysExModulators.setModulator(
|
|
513
|
+
source,
|
|
514
|
+
generatorTypes.vibLfoToPitch,
|
|
515
|
+
normalizedNotCentered * 600
|
|
516
|
+
);
|
|
517
|
+
niceLogging(
|
|
518
|
+
channel,
|
|
519
|
+
normalizedNotCentered * 600,
|
|
520
|
+
`${sourceName} LFO1 pitch depth`,
|
|
521
|
+
"cents"
|
|
522
|
+
);
|
|
523
|
+
break;
|
|
524
|
+
|
|
525
|
+
case 0x05:
|
|
526
|
+
// LFO1 filter depth
|
|
527
|
+
channelObject.sysExModulators.setModulator(
|
|
528
|
+
source,
|
|
529
|
+
generatorTypes.vibLfoToFilterFc,
|
|
530
|
+
normalizedNotCentered * 2400
|
|
531
|
+
);
|
|
532
|
+
niceLogging(
|
|
533
|
+
channel,
|
|
534
|
+
normalizedNotCentered * 2400,
|
|
535
|
+
`${sourceName} LFO1 filter depth`,
|
|
536
|
+
"cents"
|
|
537
|
+
);
|
|
538
|
+
break;
|
|
539
|
+
|
|
540
|
+
case 0x06:
|
|
541
|
+
// LFO1 amplitude depth
|
|
542
|
+
channelObject.sysExModulators.setModulator(
|
|
543
|
+
source,
|
|
544
|
+
generatorTypes.vibLfoToVolume,
|
|
545
|
+
normalizedNotCentered * 960
|
|
546
|
+
);
|
|
547
|
+
niceLogging(
|
|
548
|
+
channel,
|
|
549
|
+
normalizedNotCentered * 960,
|
|
550
|
+
`${sourceName} LFO1 amplitude depth`,
|
|
551
|
+
"cB"
|
|
552
|
+
);
|
|
553
|
+
break;
|
|
554
|
+
|
|
555
|
+
// rate control is ignored as it is in hertz
|
|
556
|
+
|
|
557
|
+
case 0x08:
|
|
558
|
+
// LFO2 pitch depth
|
|
559
|
+
channelObject.sysExModulators.setModulator(
|
|
560
|
+
source,
|
|
561
|
+
generatorTypes.modLfoToPitch,
|
|
562
|
+
normalizedNotCentered * 600
|
|
563
|
+
);
|
|
564
|
+
niceLogging(
|
|
565
|
+
channel,
|
|
566
|
+
normalizedNotCentered * 600,
|
|
567
|
+
`${sourceName} LFO2 pitch depth`,
|
|
568
|
+
"cents"
|
|
569
|
+
);
|
|
570
|
+
break;
|
|
571
|
+
|
|
572
|
+
case 0x09:
|
|
573
|
+
// LFO2 filter depth
|
|
574
|
+
channelObject.sysExModulators.setModulator(
|
|
575
|
+
source,
|
|
576
|
+
generatorTypes.modLfoToFilterFc,
|
|
577
|
+
normalizedNotCentered * 2400
|
|
578
|
+
);
|
|
579
|
+
niceLogging(
|
|
580
|
+
channel,
|
|
581
|
+
normalizedNotCentered * 2400,
|
|
582
|
+
`${sourceName} LFO2 filter depth`,
|
|
583
|
+
"cents"
|
|
584
|
+
);
|
|
585
|
+
break;
|
|
586
|
+
|
|
587
|
+
case 0x0A:
|
|
588
|
+
// LFO2 amplitude depth
|
|
589
|
+
channelObject.sysExModulators.setModulator(
|
|
590
|
+
source,
|
|
591
|
+
generatorTypes.modLfoToVolume,
|
|
592
|
+
normalizedNotCentered * 960
|
|
593
|
+
);
|
|
594
|
+
niceLogging(
|
|
595
|
+
channel,
|
|
596
|
+
normalizedNotCentered * 960,
|
|
597
|
+
`${sourceName} LFO2 amplitude depth`,
|
|
598
|
+
"cB"
|
|
599
|
+
);
|
|
600
|
+
break;
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
// SC88 manual page 198
|
|
605
|
+
switch (syx[6] & 0xF0)
|
|
606
|
+
{
|
|
607
|
+
default:
|
|
608
|
+
// this is some other GS sysex...
|
|
609
|
+
notRecognized();
|
|
610
|
+
break;
|
|
611
|
+
|
|
612
|
+
case 0x00:
|
|
613
|
+
// modulation wheel
|
|
614
|
+
setupReceivers(midiControllers.modulationWheel, "mod wheel");
|
|
615
|
+
break;
|
|
616
|
+
|
|
617
|
+
case 0x10:
|
|
618
|
+
// pitch bend
|
|
619
|
+
setupReceivers(NON_CC_INDEX_OFFSET + modulatorSources.pitchWheel, "pitch bend", true);
|
|
620
|
+
break;
|
|
621
|
+
|
|
622
|
+
case 0x20:
|
|
623
|
+
// channel pressure
|
|
624
|
+
setupReceivers(
|
|
625
|
+
NON_CC_INDEX_OFFSET + modulatorSources.channelPressure,
|
|
626
|
+
"channel pressure"
|
|
627
|
+
);
|
|
628
|
+
break;
|
|
629
|
+
|
|
630
|
+
case 0x30:
|
|
631
|
+
// poly pressure
|
|
632
|
+
setupReceivers(
|
|
633
|
+
NON_CC_INDEX_OFFSET + modulatorSources.polyPressure,
|
|
634
|
+
"poly pressure"
|
|
635
|
+
);
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
485
638
|
return;
|
|
486
639
|
}
|
|
487
|
-
else
|
|
640
|
+
else
|
|
641
|
+
// this is a global system parameter
|
|
642
|
+
if (syx[5] === 0x00)
|
|
488
643
|
{
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
644
|
+
switch (syx[6])
|
|
645
|
+
{
|
|
646
|
+
default:
|
|
647
|
+
notRecognized();
|
|
648
|
+
break;
|
|
649
|
+
|
|
650
|
+
case 0x7F:
|
|
651
|
+
// roland mode set
|
|
652
|
+
// GS mode set
|
|
653
|
+
if (messageValue === 0x00)
|
|
654
|
+
{
|
|
655
|
+
// this is a GS reset
|
|
656
|
+
SpessaSynthInfo("%cGS Reset received!", consoleColors.info);
|
|
657
|
+
this.resetAllControllers(false);
|
|
658
|
+
this.setSystem("gs");
|
|
659
|
+
}
|
|
660
|
+
else if (messageValue === 0x7F)
|
|
661
|
+
{
|
|
662
|
+
// GS mode off
|
|
663
|
+
SpessaSynthInfo("%cGS system off, switching to GM2", consoleColors.info);
|
|
664
|
+
this.resetAllControllers(false);
|
|
665
|
+
this.setSystem("gm2");
|
|
666
|
+
}
|
|
667
|
+
break;
|
|
668
|
+
|
|
669
|
+
case 0x06:
|
|
670
|
+
// roland master pan
|
|
671
|
+
SpessaSynthInfo(
|
|
672
|
+
`%cRoland GS Master Pan set to: %c${messageValue}%c with: %c${arrayToHexString(
|
|
673
|
+
syx)}`,
|
|
674
|
+
consoleColors.info,
|
|
675
|
+
consoleColors.value,
|
|
676
|
+
consoleColors.info,
|
|
677
|
+
consoleColors.value
|
|
678
|
+
);
|
|
679
|
+
this.setMasterParameter(masterParameterType.masterPan, (messageValue - 64) / 64);
|
|
680
|
+
break;
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
case 0x04:
|
|
684
|
+
// roland GS master volume
|
|
685
|
+
SpessaSynthInfo(
|
|
686
|
+
`%cRoland GS Master Volume set to: %c${messageValue}%c with: %c${arrayToHexString(
|
|
687
|
+
syx)}`,
|
|
688
|
+
consoleColors.info,
|
|
689
|
+
consoleColors.value,
|
|
690
|
+
consoleColors.info,
|
|
691
|
+
consoleColors.value
|
|
692
|
+
);
|
|
693
|
+
this.setMIDIVolume(messageValue / 127);
|
|
694
|
+
break;
|
|
695
|
+
|
|
696
|
+
case 0x05:
|
|
697
|
+
// roland master key shift (transpose)
|
|
698
|
+
const transpose = messageValue - 64;
|
|
699
|
+
SpessaSynthInfo(
|
|
700
|
+
`%cRoland GS Master Key-Shift set to: %c${transpose}%c with: %c${arrayToHexString(
|
|
701
|
+
syx)}`,
|
|
702
|
+
consoleColors.info,
|
|
703
|
+
consoleColors.value,
|
|
704
|
+
consoleColors.info,
|
|
705
|
+
consoleColors.value
|
|
706
|
+
);
|
|
707
|
+
this.setMasterTuning(transpose * 100);
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
500
710
|
return;
|
|
501
711
|
}
|
|
502
|
-
else
|
|
712
|
+
else
|
|
713
|
+
// this is a global system parameter also
|
|
714
|
+
if (syx[5] === 0x01)
|
|
503
715
|
{
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
716
|
+
switch (syx[6])
|
|
717
|
+
{
|
|
718
|
+
default:
|
|
719
|
+
notRecognized();
|
|
720
|
+
break;
|
|
721
|
+
|
|
722
|
+
case 0x00:
|
|
723
|
+
// patch name. cool!
|
|
724
|
+
syx.currentIndex = 7;
|
|
725
|
+
const patchName = readBytesAsString(syx, 16);
|
|
726
|
+
SpessaSynthInfo(
|
|
727
|
+
`%cGS Patch name: %c${patchName}`,
|
|
728
|
+
consoleColors.info,
|
|
729
|
+
consoleColors.value
|
|
730
|
+
);
|
|
731
|
+
break;
|
|
732
|
+
|
|
733
|
+
case 0x33:
|
|
734
|
+
// reverb level
|
|
735
|
+
SpessaSynthInfo(
|
|
736
|
+
`%cGS Reverb level: %c${messageValue}`,
|
|
737
|
+
consoleColors.info, consoleColors.value
|
|
738
|
+
);
|
|
739
|
+
// 64 is the default
|
|
740
|
+
this.reverbSend = messageValue / 64;
|
|
741
|
+
break;
|
|
742
|
+
|
|
743
|
+
// unsupported reverb params
|
|
744
|
+
case 0x30:
|
|
745
|
+
case 0x31:
|
|
746
|
+
case 0x32:
|
|
747
|
+
case 0x34:
|
|
748
|
+
case 0x35:
|
|
749
|
+
case 0x37:
|
|
750
|
+
SpessaSynthInfo(
|
|
751
|
+
`%cUnsupported GS Reverb Parameter: %c${syx[6].toString(16)}`,
|
|
752
|
+
consoleColors.warn, consoleColors.unrecognized
|
|
753
|
+
);
|
|
754
|
+
break;
|
|
755
|
+
|
|
756
|
+
case 0x3A:
|
|
757
|
+
// chorus level
|
|
758
|
+
SpessaSynthInfo(
|
|
759
|
+
`%cGS Chorus level: %c${messageValue}`,
|
|
760
|
+
consoleColors.info, consoleColors.value
|
|
761
|
+
);
|
|
762
|
+
// 64 is the default
|
|
763
|
+
this.chorusSend = messageValue / 64;
|
|
764
|
+
break;
|
|
765
|
+
|
|
766
|
+
// unsupported chorus params
|
|
767
|
+
case 0x38:
|
|
768
|
+
case 0x39:
|
|
769
|
+
case 0x3B:
|
|
770
|
+
case 0x3C:
|
|
771
|
+
case 0x3D:
|
|
772
|
+
case 0x3E:
|
|
773
|
+
case 0x3F:
|
|
774
|
+
case 0x40:
|
|
775
|
+
SpessaSynthInfo(
|
|
776
|
+
`%cUnsupported GS Chorus Parameter: %c${syx[6].toString(16)}`,
|
|
777
|
+
consoleColors.warn, consoleColors.unrecognized
|
|
778
|
+
);
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
515
781
|
}
|
|
516
782
|
}
|
|
517
|
-
|
|
518
|
-
|
|
783
|
+
else
|
|
784
|
+
{
|
|
785
|
+
// this is some other GS sysex...
|
|
786
|
+
notRecognized();
|
|
787
|
+
}
|
|
519
788
|
return;
|
|
520
789
|
}
|
|
521
|
-
else if (
|
|
790
|
+
else if (syx[2] === 0x45 && syx[3] === 0x12)
|
|
522
791
|
{
|
|
523
792
|
// 0x45: GS Display Data, 0x12: DT1 (Device Transmit)
|
|
524
793
|
// check for embedded copyright
|
|
525
794
|
// (roland SC display sysex) http://www.bandtrax.com.au/sysex.htm
|
|
526
795
|
|
|
527
796
|
if (
|
|
528
|
-
|
|
529
|
-
|
|
797
|
+
syx[4] === 0x10 && // Sound Canvas Display
|
|
798
|
+
syx[6] === 0x00 // Data follows
|
|
530
799
|
)
|
|
531
800
|
{
|
|
532
|
-
if (
|
|
801
|
+
if (syx[5] === 0x00) // Display letters
|
|
533
802
|
{
|
|
534
803
|
// get the text
|
|
535
804
|
// and header ends with (checksum) F7
|
|
536
|
-
const text = new Uint8Array(
|
|
805
|
+
const text = new Uint8Array(syx.slice(7, syx.length - 2));
|
|
537
806
|
this.callEvent(
|
|
538
807
|
"synthdisplay",
|
|
539
808
|
{
|
|
@@ -542,11 +811,11 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
542
811
|
}
|
|
543
812
|
);
|
|
544
813
|
}
|
|
545
|
-
else if (
|
|
814
|
+
else if (syx[5] === 0x01) // Matrix display
|
|
546
815
|
{
|
|
547
816
|
// get the data
|
|
548
817
|
// and header ends with (checksum) F7
|
|
549
|
-
const dotMatrixData = new Uint8Array(
|
|
818
|
+
const dotMatrixData = new Uint8Array(syx.slice(7, syx.length - 3));
|
|
550
819
|
this.callEvent(
|
|
551
820
|
"synthdisplay",
|
|
552
821
|
{
|
|
@@ -556,7 +825,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
556
825
|
);
|
|
557
826
|
SpessaSynthInfo(
|
|
558
827
|
`%cRoland SC Display Dot Matrix via: %c${arrayToHexString(
|
|
559
|
-
|
|
828
|
+
syx)}`,
|
|
560
829
|
consoleColors.info,
|
|
561
830
|
consoleColors.value
|
|
562
831
|
);
|
|
@@ -568,13 +837,13 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
568
837
|
}
|
|
569
838
|
}
|
|
570
839
|
}
|
|
571
|
-
else if (
|
|
840
|
+
else if (syx[2] === 0x16 && syx[3] === 0x12 && syx[4] === 0x10)
|
|
572
841
|
{
|
|
573
842
|
// this is a roland master volume message
|
|
574
|
-
this.setMIDIVolume(
|
|
843
|
+
this.setMIDIVolume(syx[7] / 100);
|
|
575
844
|
SpessaSynthInfo(
|
|
576
|
-
`%cRoland Master Volume control set to: %c${
|
|
577
|
-
|
|
845
|
+
`%cRoland Master Volume control set to: %c${syx[7]}%c via: %c${arrayToHexString(
|
|
846
|
+
syx)}`,
|
|
578
847
|
consoleColors.info,
|
|
579
848
|
consoleColors.value,
|
|
580
849
|
consoleColors.info,
|
|
@@ -586,7 +855,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
586
855
|
{
|
|
587
856
|
// this is something else...
|
|
588
857
|
SpessaSynthWarn(
|
|
589
|
-
`%cUnrecognized Roland SysEx: %c${arrayToHexString(
|
|
858
|
+
`%cUnrecognized Roland SysEx: %c${arrayToHexString(syx)}`,
|
|
590
859
|
consoleColors.warn,
|
|
591
860
|
consoleColors.unrecognized
|
|
592
861
|
);
|
|
@@ -598,16 +867,16 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
598
867
|
// http://www.studio4all.de/htmle/main91.html
|
|
599
868
|
case 0x43:
|
|
600
869
|
// XG sysex
|
|
601
|
-
if (
|
|
870
|
+
if (syx[2] === 0x4C)
|
|
602
871
|
{
|
|
603
872
|
// XG system parameter
|
|
604
|
-
if (
|
|
873
|
+
if (syx[3] === 0x00 && syx[4] === 0x00)
|
|
605
874
|
{
|
|
606
|
-
switch (
|
|
875
|
+
switch (syx[5])
|
|
607
876
|
{
|
|
608
877
|
// master volume
|
|
609
878
|
case 0x04:
|
|
610
|
-
const vol =
|
|
879
|
+
const vol = syx[6];
|
|
611
880
|
this.setMIDIVolume(vol / 127);
|
|
612
881
|
SpessaSynthInfo(
|
|
613
882
|
`%cXG master volume. Volume: %c${vol}`,
|
|
@@ -618,7 +887,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
618
887
|
|
|
619
888
|
// master transpose
|
|
620
889
|
case 0x06:
|
|
621
|
-
const transpose =
|
|
890
|
+
const transpose = syx[6] - 64;
|
|
622
891
|
this.transposeAllChannels(transpose);
|
|
623
892
|
SpessaSynthInfo(
|
|
624
893
|
`%cXG master transpose. Volume: %c${transpose}`,
|
|
@@ -637,21 +906,21 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
637
906
|
}
|
|
638
907
|
else
|
|
639
908
|
// XG part parameter
|
|
640
|
-
if (
|
|
909
|
+
if (syx[3] === 0x08)
|
|
641
910
|
{
|
|
642
911
|
if (!isSystemXG(this.system))
|
|
643
912
|
{
|
|
644
913
|
return;
|
|
645
914
|
}
|
|
646
|
-
const channel =
|
|
915
|
+
const channel = syx[4] + channelOffset;
|
|
647
916
|
if (channel >= this.midiAudioChannels.length)
|
|
648
917
|
{
|
|
649
918
|
// invalid channel
|
|
650
919
|
return;
|
|
651
920
|
}
|
|
652
921
|
const channelObject = this.midiAudioChannels[channel];
|
|
653
|
-
const value =
|
|
654
|
-
switch (
|
|
922
|
+
const value = syx[6];
|
|
923
|
+
switch (syx[5])
|
|
655
924
|
{
|
|
656
925
|
// bank-select MSB
|
|
657
926
|
case 0x01:
|
|
@@ -716,7 +985,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
716
985
|
|
|
717
986
|
default:
|
|
718
987
|
SpessaSynthWarn(
|
|
719
|
-
`%cUnrecognized Yamaha XG Part Setup: %c${
|
|
988
|
+
`%cUnrecognized Yamaha XG Part Setup: %c${syx[5].toString(16)
|
|
720
989
|
.toUpperCase()}`,
|
|
721
990
|
consoleColors.warn,
|
|
722
991
|
consoleColors.unrecognized
|
|
@@ -724,13 +993,13 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
724
993
|
}
|
|
725
994
|
}
|
|
726
995
|
else if (
|
|
727
|
-
|
|
728
|
-
|
|
996
|
+
syx[3] === 0x06 && // XG System parameter
|
|
997
|
+
syx[4] === 0x00 // System Byte
|
|
729
998
|
)
|
|
730
999
|
{
|
|
731
1000
|
// displayed letters (remove F7 at the end)
|
|
732
1001
|
// include byte 5 as it seems to be line information (useful)
|
|
733
|
-
const textData = new Uint8Array(
|
|
1002
|
+
const textData = new Uint8Array(syx.slice(5, syx.length - 1));
|
|
734
1003
|
this.callEvent(
|
|
735
1004
|
"synthdisplay",
|
|
736
1005
|
{
|
|
@@ -742,7 +1011,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
742
1011
|
else if (isSystemXG(this.system))
|
|
743
1012
|
{
|
|
744
1013
|
SpessaSynthWarn(
|
|
745
|
-
`%cUnrecognized Yamaha XG SysEx: %c${arrayToHexString(
|
|
1014
|
+
`%cUnrecognized Yamaha XG SysEx: %c${arrayToHexString(syx)}`,
|
|
746
1015
|
consoleColors.warn,
|
|
747
1016
|
consoleColors.unrecognized
|
|
748
1017
|
);
|
|
@@ -754,7 +1023,7 @@ export function systemExclusive(messageData, channelOffset = 0)
|
|
|
754
1023
|
if (isSystemXG(this.system))
|
|
755
1024
|
{
|
|
756
1025
|
SpessaSynthWarn(
|
|
757
|
-
`%cUnrecognized Yamaha SysEx: %c${arrayToHexString(
|
|
1026
|
+
`%cUnrecognized Yamaha SysEx: %c${arrayToHexString(syx)}`,
|
|
758
1027
|
consoleColors.warn,
|
|
759
1028
|
consoleColors.unrecognized
|
|
760
1029
|
);
|