spessasynth_core 1.1.2 → 1.1.4
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/LICENSE +3 -26
- package/README.md +156 -474
- package/index.js +73 -8
- package/package.json +21 -8
- package/src/externals/fflate/LICENSE +21 -0
- package/src/externals/fflate/fflate.min.js +1 -0
- package/src/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +12 -0
- package/src/externals/stbvorbis_sync/LICENSE +202 -0
- package/src/externals/stbvorbis_sync/NOTICE +6 -0
- package/src/externals/stbvorbis_sync/stbvorbis_sync.min.js +1 -0
- package/src/midi/README.md +32 -0
- package/src/midi/basic_midi.js +567 -0
- package/src/midi/midi_builder.js +202 -0
- package/src/midi/midi_loader.js +324 -0
- package/{spessasynth_core/midi_parser → src/midi}/midi_message.js +58 -35
- package/src/midi/midi_sequence.js +224 -0
- package/src/midi/midi_tools/get_note_times.js +154 -0
- package/src/midi/midi_tools/midi_editor.js +611 -0
- package/src/midi/midi_tools/midi_writer.js +99 -0
- package/src/midi/midi_tools/rmidi_writer.js +567 -0
- package/src/midi/midi_tools/used_keys_loaded.js +238 -0
- package/src/midi/xmf_loader.js +454 -0
- package/src/sequencer/README.md +5 -0
- package/src/sequencer/events.js +81 -0
- package/src/sequencer/play.js +349 -0
- package/src/sequencer/process_event.js +165 -0
- package/{spessasynth_core/sequencer/worklet_sequencer → src/sequencer}/process_tick.js +103 -84
- package/src/sequencer/sequencer_engine.js +367 -0
- package/src/sequencer/song_control.js +201 -0
- package/src/soundfont/README.md +13 -0
- package/src/soundfont/basic_soundfont/basic_instrument.js +77 -0
- package/src/soundfont/basic_soundfont/basic_preset.js +336 -0
- package/src/soundfont/basic_soundfont/basic_sample.js +206 -0
- package/src/soundfont/basic_soundfont/basic_soundfont.js +565 -0
- package/src/soundfont/basic_soundfont/basic_zone.js +64 -0
- package/src/soundfont/basic_soundfont/basic_zones.js +43 -0
- package/src/soundfont/basic_soundfont/generator.js +220 -0
- package/src/soundfont/basic_soundfont/modulator.js +378 -0
- package/src/soundfont/basic_soundfont/riff_chunk.js +149 -0
- package/src/soundfont/basic_soundfont/write_dls/art2.js +173 -0
- package/src/soundfont/basic_soundfont/write_dls/articulator.js +49 -0
- package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +400 -0
- package/src/soundfont/basic_soundfont/write_dls/ins.js +103 -0
- package/src/soundfont/basic_soundfont/write_dls/lins.js +18 -0
- package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +330 -0
- package/src/soundfont/basic_soundfont/write_dls/rgn2.js +121 -0
- package/src/soundfont/basic_soundfont/write_dls/wave.js +94 -0
- package/src/soundfont/basic_soundfont/write_dls/write_dls.js +119 -0
- package/src/soundfont/basic_soundfont/write_dls/wsmp.js +78 -0
- package/src/soundfont/basic_soundfont/write_dls/wvpl.js +32 -0
- package/src/soundfont/basic_soundfont/write_sf2/ibag.js +39 -0
- package/src/soundfont/basic_soundfont/write_sf2/igen.js +80 -0
- package/src/soundfont/basic_soundfont/write_sf2/imod.js +46 -0
- package/src/soundfont/basic_soundfont/write_sf2/inst.js +34 -0
- package/src/soundfont/basic_soundfont/write_sf2/pbag.js +39 -0
- package/src/soundfont/basic_soundfont/write_sf2/pgen.js +82 -0
- package/src/soundfont/basic_soundfont/write_sf2/phdr.js +42 -0
- package/src/soundfont/basic_soundfont/write_sf2/pmod.js +46 -0
- package/src/soundfont/basic_soundfont/write_sf2/sdta.js +80 -0
- package/src/soundfont/basic_soundfont/write_sf2/shdr.js +55 -0
- package/src/soundfont/basic_soundfont/write_sf2/write.js +222 -0
- package/src/soundfont/dls/articulator_converter.js +396 -0
- package/src/soundfont/dls/dls_destinations.js +38 -0
- package/src/soundfont/dls/dls_preset.js +44 -0
- package/src/soundfont/dls/dls_sample.js +75 -0
- package/src/soundfont/dls/dls_soundfont.js +186 -0
- package/src/soundfont/dls/dls_sources.js +62 -0
- package/src/soundfont/dls/dls_zone.js +95 -0
- package/src/soundfont/dls/read_articulation.js +299 -0
- package/src/soundfont/dls/read_instrument.js +121 -0
- package/src/soundfont/dls/read_instrument_list.js +17 -0
- package/src/soundfont/dls/read_lart.js +35 -0
- package/src/soundfont/dls/read_region.js +152 -0
- package/src/soundfont/dls/read_samples.js +270 -0
- package/src/soundfont/load_soundfont.js +21 -0
- package/src/soundfont/read_sf2/generators.js +46 -0
- package/{spessasynth_core/soundfont/chunk → src/soundfont/read_sf2}/instruments.js +20 -14
- package/src/soundfont/read_sf2/modulators.js +36 -0
- package/src/soundfont/read_sf2/presets.js +80 -0
- package/src/soundfont/read_sf2/samples.js +304 -0
- package/src/soundfont/read_sf2/soundfont.js +305 -0
- package/{spessasynth_core/soundfont/chunk → src/soundfont/read_sf2}/zones.js +68 -69
- package/src/synthetizer/README.md +7 -0
- package/src/synthetizer/audio_engine/README.md +9 -0
- package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +266 -0
- package/src/synthetizer/audio_engine/engine_components/controller_tables.js +88 -0
- package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +150 -0
- package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/lfo.js +9 -6
- package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +282 -0
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +467 -0
- package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +181 -0
- package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/modulator_curves.js +33 -30
- package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +221 -0
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +120 -0
- package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/unit_converter.js +11 -4
- package/src/synthetizer/audio_engine/engine_components/voice.js +519 -0
- package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +401 -0
- package/src/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +263 -0
- package/src/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +132 -0
- package/src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +48 -0
- package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +241 -0
- package/src/synthetizer/audio_engine/engine_methods/create_midi_channel.js +27 -0
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +253 -0
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +66 -0
- package/src/synthetizer/audio_engine/engine_methods/mute_channel.js +17 -0
- package/src/synthetizer/audio_engine/engine_methods/note_on.js +175 -0
- package/src/synthetizer/audio_engine/engine_methods/portamento_time.js +92 -0
- package/src/synthetizer/audio_engine/engine_methods/program_change.js +61 -0
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +196 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +30 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +22 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +28 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +31 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +21 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +20 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +55 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +16 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +30 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +63 -0
- package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +776 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +24 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +33 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +31 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +15 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +27 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +19 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +27 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +15 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +34 -0
- package/src/synthetizer/audio_engine/main_processor.js +804 -0
- package/src/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +15 -0
- package/src/synthetizer/audio_engine/snapshot/channel_snapshot.js +175 -0
- package/src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +116 -0
- package/src/synthetizer/synth_constants.js +22 -0
- package/{spessasynth_core → src}/utils/README.md +1 -0
- package/src/utils/buffer_to_wav.js +185 -0
- package/src/utils/byte_functions/big_endian.js +32 -0
- package/src/utils/byte_functions/little_endian.js +77 -0
- package/src/utils/byte_functions/string.js +107 -0
- package/src/utils/byte_functions/variable_length_quantity.js +42 -0
- package/src/utils/fill_with_defaults.js +21 -0
- package/src/utils/indexed_array.js +52 -0
- package/{spessasynth_core → src}/utils/loggin.js +70 -78
- package/src/utils/other.js +92 -0
- package/src/utils/sysex_detector.js +58 -0
- package/src/utils/xg_hacks.js +193 -0
- package/.idea/inspectionProfiles/Project_Default.xml +0 -10
- package/.idea/jsLibraryMappings.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/spessasynth_core.iml +0 -12
- package/.idea/vcs.xml +0 -6
- package/spessasynth_core/midi_parser/README.md +0 -3
- package/spessasynth_core/midi_parser/midi_loader.js +0 -386
- package/spessasynth_core/sequencer/sequencer.js +0 -202
- package/spessasynth_core/sequencer/worklet_sequencer/play.js +0 -209
- package/spessasynth_core/sequencer/worklet_sequencer/process_event.js +0 -120
- package/spessasynth_core/sequencer/worklet_sequencer/song_control.js +0 -112
- package/spessasynth_core/soundfont/README.md +0 -4
- package/spessasynth_core/soundfont/chunk/generators.js +0 -205
- package/spessasynth_core/soundfont/chunk/modulators.js +0 -232
- package/spessasynth_core/soundfont/chunk/presets.js +0 -264
- package/spessasynth_core/soundfont/chunk/riff_chunk.js +0 -46
- package/spessasynth_core/soundfont/chunk/samples.js +0 -250
- package/spessasynth_core/soundfont/soundfont_parser.js +0 -301
- package/spessasynth_core/synthetizer/README.md +0 -6
- package/spessasynth_core/synthetizer/synthesizer.js +0 -303
- package/spessasynth_core/synthetizer/worklet_system/README.md +0 -3
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/controller_control.js +0 -290
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/data_entry.js +0 -280
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/note_off.js +0 -102
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/note_on.js +0 -77
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/program_control.js +0 -140
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/system_exclusive.js +0 -266
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/tuning_control.js +0 -104
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/vibrato_control.js +0 -29
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/voice_control.js +0 -222
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +0 -95
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/modulation_envelope.js +0 -73
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +0 -76
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/volume_envelope.js +0 -194
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/wavetable_oscillator.js +0 -83
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_modulator.js +0 -173
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +0 -106
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +0 -313
- package/spessasynth_core/utils/buffer_to_wav.js +0 -70
- package/spessasynth_core/utils/byte_functions.js +0 -141
- package/spessasynth_core/utils/other.js +0 -49
- package/spessasynth_core/utils/shiftable_array.js +0 -26
- package/spessasynth_core/utils/stbvorbis_sync.js +0 -1877
|
@@ -0,0 +1,776 @@
|
|
|
1
|
+
import { arrayToHexString, consoleColors } from "../../../utils/other.js";
|
|
2
|
+
import { SpessaSynthInfo, SpessaSynthWarn } from "../../../utils/loggin.js";
|
|
3
|
+
import { midiControllers } from "../../../midi/midi_message.js";
|
|
4
|
+
import { ALL_CHANNELS_OR_DIFFERENT_ACTION } from "../../synth_constants.js";
|
|
5
|
+
import { isSystemXG } from "../../../utils/xg_hacks.js";
|
|
6
|
+
import { masterParameterType } from "./controller_control/master_parameters.js";
|
|
7
|
+
import { readBytesAsString } from "../../../utils/byte_functions/string.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* KeyNum: tuning
|
|
11
|
+
* @typedef {MTSNoteTuning[]} MTSProgramTuning
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} MTSNoteTuning
|
|
16
|
+
* @property {number} midiNote - the base midi note to use, -1 means no change
|
|
17
|
+
* @property {number} centTuning - additional tuning
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Calculates freqency for MIDI Tuning Standard
|
|
22
|
+
* @param byte1 {number}
|
|
23
|
+
* @param byte2 {number}
|
|
24
|
+
* @param byte3 {number}
|
|
25
|
+
* @return {{midiNote: number, centTuning: number|null}}
|
|
26
|
+
*/
|
|
27
|
+
function getTuning(byte1, byte2, byte3)
|
|
28
|
+
{
|
|
29
|
+
const midiNote = byte1;
|
|
30
|
+
const fraction = (byte2 << 7) | byte3; // Combine byte2 and byte3 into a 14-bit number
|
|
31
|
+
|
|
32
|
+
// no change
|
|
33
|
+
if (byte1 === 0x7F && byte2 === 0x7F && byte3 === 0x7F)
|
|
34
|
+
{
|
|
35
|
+
return { midiNote: -1, centTuning: null };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// calculate cent tuning
|
|
39
|
+
return { midiNote: midiNote, centTuning: fraction * 0.0061 };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The text types for the synth display
|
|
44
|
+
* @enum {number}
|
|
45
|
+
*/
|
|
46
|
+
export const SynthDisplayType = {
|
|
47
|
+
SoundCanvasText: 0,
|
|
48
|
+
XGText: 1,
|
|
49
|
+
SoundCanvasDotDisplay: 2
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Executes a system exclusive
|
|
55
|
+
* @param messageData {number[]|IndexedByteArray} - the message data without f0
|
|
56
|
+
* @param channelOffset {number}
|
|
57
|
+
* @this {SpessaSynthProcessor}
|
|
58
|
+
*/
|
|
59
|
+
export function systemExclusive(messageData, channelOffset = 0)
|
|
60
|
+
{
|
|
61
|
+
const type = messageData[0];
|
|
62
|
+
if (this.deviceID !== ALL_CHANNELS_OR_DIFFERENT_ACTION && messageData[1] !== 0x7F)
|
|
63
|
+
{
|
|
64
|
+
if (this.deviceID !== messageData[1])
|
|
65
|
+
{
|
|
66
|
+
// not our device ID
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
switch (type)
|
|
71
|
+
{
|
|
72
|
+
default:
|
|
73
|
+
SpessaSynthWarn(
|
|
74
|
+
`%cUnrecognized SysEx: %c${arrayToHexString(messageData)}`,
|
|
75
|
+
consoleColors.warn,
|
|
76
|
+
consoleColors.unrecognized
|
|
77
|
+
);
|
|
78
|
+
break;
|
|
79
|
+
|
|
80
|
+
// non realtime
|
|
81
|
+
case 0x7E:
|
|
82
|
+
case 0x7F:
|
|
83
|
+
switch (messageData[2])
|
|
84
|
+
{
|
|
85
|
+
case 0x04:
|
|
86
|
+
let cents;
|
|
87
|
+
// device control
|
|
88
|
+
switch (messageData[3])
|
|
89
|
+
{
|
|
90
|
+
case 0x01:
|
|
91
|
+
// main volume
|
|
92
|
+
const vol = messageData[5] << 7 | messageData[4];
|
|
93
|
+
this.setMIDIVolume(vol / 16384);
|
|
94
|
+
SpessaSynthInfo(
|
|
95
|
+
`%cMaster Volume. Volume: %c${vol}`,
|
|
96
|
+
consoleColors.info,
|
|
97
|
+
consoleColors.value
|
|
98
|
+
);
|
|
99
|
+
break;
|
|
100
|
+
|
|
101
|
+
case 0x02:
|
|
102
|
+
// main balance
|
|
103
|
+
// midi spec page 62
|
|
104
|
+
const balance = messageData[5] << 7 | messageData[4];
|
|
105
|
+
const pan = (balance - 8192) / 8192;
|
|
106
|
+
this.setMasterParameter(masterParameterType.masterPan, pan);
|
|
107
|
+
SpessaSynthInfo(
|
|
108
|
+
`%cMaster Pan. Pan: %c${pan}`,
|
|
109
|
+
consoleColors.info,
|
|
110
|
+
consoleColors.value
|
|
111
|
+
);
|
|
112
|
+
break;
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
case 0x03:
|
|
116
|
+
// fine-tuning
|
|
117
|
+
const tuningValue = ((messageData[5] << 7) | messageData[6]) - 8192;
|
|
118
|
+
cents = Math.floor(tuningValue / 81.92); // [-100;+99] cents range
|
|
119
|
+
this.setMasterTuning(cents);
|
|
120
|
+
SpessaSynthInfo(
|
|
121
|
+
`%cMaster Fine Tuning. Cents: %c${cents}`,
|
|
122
|
+
consoleColors.info,
|
|
123
|
+
consoleColors.value
|
|
124
|
+
);
|
|
125
|
+
break;
|
|
126
|
+
|
|
127
|
+
case 0x04:
|
|
128
|
+
// coarse tuning
|
|
129
|
+
// lsb is ignored
|
|
130
|
+
const semitones = messageData[5] - 64;
|
|
131
|
+
cents = semitones * 100;
|
|
132
|
+
this.setMasterTuning(cents);
|
|
133
|
+
SpessaSynthInfo(
|
|
134
|
+
`%cMaster Coarse Tuning. Cents: %c${cents}`,
|
|
135
|
+
consoleColors.info,
|
|
136
|
+
consoleColors.value
|
|
137
|
+
);
|
|
138
|
+
break;
|
|
139
|
+
|
|
140
|
+
default:
|
|
141
|
+
SpessaSynthWarn(
|
|
142
|
+
`%cUnrecognized MIDI Device Control Real-time message: %c${arrayToHexString(messageData)}`,
|
|
143
|
+
consoleColors.warn,
|
|
144
|
+
consoleColors.unrecognized
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
|
|
149
|
+
case 0x09:
|
|
150
|
+
// gm system related
|
|
151
|
+
if (messageData[3] === 0x01)
|
|
152
|
+
{
|
|
153
|
+
SpessaSynthInfo("%cGM1 system on", consoleColors.info);
|
|
154
|
+
this.setSystem("gm");
|
|
155
|
+
}
|
|
156
|
+
else if (messageData[3] === 0x03)
|
|
157
|
+
{
|
|
158
|
+
SpessaSynthInfo("%cGM2 system on", consoleColors.info);
|
|
159
|
+
this.setSystem("gm2");
|
|
160
|
+
}
|
|
161
|
+
else
|
|
162
|
+
{
|
|
163
|
+
SpessaSynthInfo("%cGM system off, defaulting to GS", consoleColors.info);
|
|
164
|
+
this.setSystem("gs");
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
|
|
168
|
+
// MIDI Tuning standard
|
|
169
|
+
// https://midi.org/midi-tuning-updated-specification
|
|
170
|
+
case 0x08:
|
|
171
|
+
let currentMessageIndex = 4;
|
|
172
|
+
switch (messageData[3])
|
|
173
|
+
{
|
|
174
|
+
// bulk tuning dump: all 128 notes
|
|
175
|
+
case 0x01:
|
|
176
|
+
const program = messageData[currentMessageIndex++];
|
|
177
|
+
// read the name
|
|
178
|
+
messageData.currentIndex = currentMessageIndex;
|
|
179
|
+
const tuningName = readBytesAsString(messageData, 16);
|
|
180
|
+
currentMessageIndex += 16;
|
|
181
|
+
if (messageData.length < 384)
|
|
182
|
+
{
|
|
183
|
+
SpessaSynthWarn(`The Bulk Tuning Dump is too short! (${messageData.length} bytes, at least 384 are expected)`);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
// 128 frequencies follow
|
|
187
|
+
for (let i = 0; i < 128; i++)
|
|
188
|
+
{
|
|
189
|
+
// set the given tuning to the program
|
|
190
|
+
this.tunings[program][i] = getTuning(
|
|
191
|
+
messageData[currentMessageIndex++],
|
|
192
|
+
messageData[currentMessageIndex++],
|
|
193
|
+
messageData[currentMessageIndex++]
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
SpessaSynthInfo(
|
|
197
|
+
`%cBulk Tuning Dump %c${tuningName}%c Program: %c${program}`,
|
|
198
|
+
consoleColors.info,
|
|
199
|
+
consoleColors.value,
|
|
200
|
+
consoleColors.info,
|
|
201
|
+
consoleColors.recognized
|
|
202
|
+
);
|
|
203
|
+
break;
|
|
204
|
+
|
|
205
|
+
// single note change
|
|
206
|
+
// single note change bank
|
|
207
|
+
case 0x02:
|
|
208
|
+
case 0x07:
|
|
209
|
+
if (messageData[3] === 0x07)
|
|
210
|
+
{
|
|
211
|
+
// skip the bank
|
|
212
|
+
currentMessageIndex++;
|
|
213
|
+
}
|
|
214
|
+
// get program and number of changes
|
|
215
|
+
const tuningProgram = messageData[currentMessageIndex++];
|
|
216
|
+
const numberOfChanges = messageData[currentMessageIndex++];
|
|
217
|
+
for (let i = 0; i < numberOfChanges; i++)
|
|
218
|
+
{
|
|
219
|
+
// set the given tuning to the program
|
|
220
|
+
this.tunings[tuningProgram][messageData[currentMessageIndex++]] = getTuning(
|
|
221
|
+
messageData[currentMessageIndex++],
|
|
222
|
+
messageData[currentMessageIndex++],
|
|
223
|
+
messageData[currentMessageIndex++]
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
SpessaSynthInfo(
|
|
227
|
+
`%cSingle Note Tuning. Program: %c${tuningProgram}%c Keys affected: %c${numberOfChanges}`,
|
|
228
|
+
consoleColors.info,
|
|
229
|
+
consoleColors.recognized,
|
|
230
|
+
consoleColors.info,
|
|
231
|
+
consoleColors.recognized
|
|
232
|
+
);
|
|
233
|
+
break;
|
|
234
|
+
|
|
235
|
+
// octave tuning (1 byte)
|
|
236
|
+
// and octave tuning (2 bytes)
|
|
237
|
+
case 0x09:
|
|
238
|
+
case 0x08:
|
|
239
|
+
// get tuning:
|
|
240
|
+
const newOctaveTuning = new Int8Array(12);
|
|
241
|
+
// start from bit 7
|
|
242
|
+
if (messageData[3] === 0x08)
|
|
243
|
+
{
|
|
244
|
+
// 1 byte tuning: 0 is -64 cents, 64 is 0, 127 is +63
|
|
245
|
+
for (let i = 0; i < 12; i++)
|
|
246
|
+
{
|
|
247
|
+
newOctaveTuning[i] = messageData[7 + i] - 64;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else
|
|
251
|
+
{
|
|
252
|
+
// 2 byte tuning. Like fine tune: 0 is -100 cents, 8192 is 0 cents, 16,383 is +100 cents
|
|
253
|
+
for (let i = 0; i < 24; i += 2)
|
|
254
|
+
{
|
|
255
|
+
const tuning = ((messageData[7 + i] << 7) | messageData[8 + i]) - 8192;
|
|
256
|
+
newOctaveTuning[i / 2] = Math.floor(tuning / 81.92); // map to [-100;+99] cents
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// apply to channels (ordered from 0)
|
|
260
|
+
// bit 1: 14 and 15
|
|
261
|
+
if ((messageData[4] & 1) === 1)
|
|
262
|
+
{
|
|
263
|
+
this.midiAudioChannels[14 + channelOffset].setOctaveTuning(newOctaveTuning);
|
|
264
|
+
}
|
|
265
|
+
if (((messageData[4] >> 1) & 1) === 1)
|
|
266
|
+
{
|
|
267
|
+
this.midiAudioChannels[15 + channelOffset].setOctaveTuning(newOctaveTuning);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// bit 2: channels 7 to 13
|
|
271
|
+
for (let i = 0; i < 7; i++)
|
|
272
|
+
{
|
|
273
|
+
const bit = (messageData[5] >> i) & 1;
|
|
274
|
+
if (bit === 1)
|
|
275
|
+
{
|
|
276
|
+
this.midiAudioChannels[7 + i + channelOffset].setOctaveTuning(newOctaveTuning);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// bit 3: channels 0 to 16
|
|
281
|
+
for (let i = 0; i < 7; i++)
|
|
282
|
+
{
|
|
283
|
+
const bit = (messageData[6] >> i) & 1;
|
|
284
|
+
if (bit === 1)
|
|
285
|
+
{
|
|
286
|
+
this.midiAudioChannels[i + channelOffset].setOctaveTuning(newOctaveTuning);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
SpessaSynthInfo(
|
|
291
|
+
`%cMIDI Octave Scale ${
|
|
292
|
+
messageData[3] === 0x08 ? "(1 byte)" : "(2 bytes)"
|
|
293
|
+
} tuning via Tuning: %c${newOctaveTuning.join(" ")}`,
|
|
294
|
+
consoleColors.info,
|
|
295
|
+
consoleColors.value
|
|
296
|
+
);
|
|
297
|
+
break;
|
|
298
|
+
|
|
299
|
+
default:
|
|
300
|
+
SpessaSynthWarn(
|
|
301
|
+
`%cUnrecognized MIDI Tuning standard message: %c${arrayToHexString(messageData)}`,
|
|
302
|
+
consoleColors.warn,
|
|
303
|
+
consoleColors.unrecognized
|
|
304
|
+
);
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
break;
|
|
308
|
+
|
|
309
|
+
default:
|
|
310
|
+
SpessaSynthWarn(
|
|
311
|
+
`%cUnrecognized MIDI Realtime/non realtime message: %c${arrayToHexString(messageData)}`,
|
|
312
|
+
consoleColors.warn,
|
|
313
|
+
consoleColors.unrecognized
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
}
|
|
317
|
+
break;
|
|
318
|
+
|
|
319
|
+
// this is a roland sysex
|
|
320
|
+
// http://www.bandtrax.com.au/sysex.htm
|
|
321
|
+
// https://cdn.roland.com/assets/media/pdf/AT-20R_30R_MI.pdf
|
|
322
|
+
case 0x41:
|
|
323
|
+
|
|
324
|
+
function notRecognized()
|
|
325
|
+
{
|
|
326
|
+
// this is some other GS sysex...
|
|
327
|
+
SpessaSynthWarn(
|
|
328
|
+
`%cUnrecognized Roland %cGS %cSysEx: %c${arrayToHexString(messageData)}`,
|
|
329
|
+
consoleColors.warn,
|
|
330
|
+
consoleColors.recognized,
|
|
331
|
+
consoleColors.warn,
|
|
332
|
+
consoleColors.unrecognized
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (messageData[2] === 0x42 && messageData[3] === 0x12)
|
|
337
|
+
{
|
|
338
|
+
// this is a GS sysex
|
|
339
|
+
// messageData[5] and [6] is the system parameter, messageData[7] is the value
|
|
340
|
+
const messageValue = messageData[7];
|
|
341
|
+
if (messageData[6] === 0x7F)
|
|
342
|
+
{
|
|
343
|
+
// GS mode set
|
|
344
|
+
if (messageValue === 0x00)
|
|
345
|
+
{
|
|
346
|
+
// this is a GS reset
|
|
347
|
+
SpessaSynthInfo("%cGS Reset received!", consoleColors.info);
|
|
348
|
+
this.resetAllControllers(false);
|
|
349
|
+
this.setSystem("gs");
|
|
350
|
+
}
|
|
351
|
+
else if (messageValue === 0x7F)
|
|
352
|
+
{
|
|
353
|
+
// GS mode off
|
|
354
|
+
SpessaSynthInfo("%cGS system off, switching to GM2", consoleColors.info);
|
|
355
|
+
this.resetAllControllers(false);
|
|
356
|
+
this.setSystem("gm2");
|
|
357
|
+
}
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
else if (messageData[4] === 0x40)
|
|
361
|
+
{
|
|
362
|
+
// this is a system parameter
|
|
363
|
+
if ((messageData[5] & 0x10) > 0)
|
|
364
|
+
{
|
|
365
|
+
// this is an individual part (channel) parameter
|
|
366
|
+
// determine the channel 0 means channel 10 (default), 1 means 1 etc.
|
|
367
|
+
const channel = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15][messageData[5] & 0x0F] + channelOffset;
|
|
368
|
+
// for example, 0x1A means A = 11, which corresponds to channel 12 (counting from 1)
|
|
369
|
+
const channelObject = this.midiAudioChannels[channel];
|
|
370
|
+
switch (messageData[6])
|
|
371
|
+
{
|
|
372
|
+
default:
|
|
373
|
+
// this is some other GS sysex...
|
|
374
|
+
notRecognized();
|
|
375
|
+
break;
|
|
376
|
+
|
|
377
|
+
case 0x15:
|
|
378
|
+
// this is the Use for Drum Part sysex (multiple drums)
|
|
379
|
+
const isDrums = messageValue > 0 && messageData[5] >> 4; // if set to other than 0, is a drum channel
|
|
380
|
+
channelObject.setDrums(isDrums);
|
|
381
|
+
SpessaSynthInfo(
|
|
382
|
+
`%cChannel %c${channel}%c ${isDrums ?
|
|
383
|
+
"is now a drum channel"
|
|
384
|
+
:
|
|
385
|
+
"now isn't a drum channel"
|
|
386
|
+
}%c via: %c${arrayToHexString(messageData)}`,
|
|
387
|
+
consoleColors.info,
|
|
388
|
+
consoleColors.value,
|
|
389
|
+
consoleColors.recognized,
|
|
390
|
+
consoleColors.info,
|
|
391
|
+
consoleColors.value
|
|
392
|
+
);
|
|
393
|
+
return;
|
|
394
|
+
|
|
395
|
+
case 0x16:
|
|
396
|
+
// this is the pitch key shift sysex
|
|
397
|
+
const keyShift = messageValue - 64;
|
|
398
|
+
channelObject.transposeChannel(keyShift);
|
|
399
|
+
SpessaSynthInfo(
|
|
400
|
+
`%cChannel %c${channel}%c pitch shift. Semitones %c${keyShift}%c, with %c${arrayToHexString(
|
|
401
|
+
messageData)}`,
|
|
402
|
+
consoleColors.info,
|
|
403
|
+
consoleColors.recognized,
|
|
404
|
+
consoleColors.info,
|
|
405
|
+
consoleColors.value,
|
|
406
|
+
consoleColors.info,
|
|
407
|
+
consoleColors.value
|
|
408
|
+
);
|
|
409
|
+
return;
|
|
410
|
+
|
|
411
|
+
// pan position
|
|
412
|
+
case 0x1C:
|
|
413
|
+
// 0 is random
|
|
414
|
+
let panpot = messageValue;
|
|
415
|
+
if (panpot === 0)
|
|
416
|
+
{
|
|
417
|
+
channelObject.randomPan = true;
|
|
418
|
+
SpessaSynthInfo(
|
|
419
|
+
`%cRandom pan is set to %cON%c for %c${channel}`,
|
|
420
|
+
consoleColors.info,
|
|
421
|
+
consoleColors.recognized,
|
|
422
|
+
consoleColors.info,
|
|
423
|
+
consoleColors.value
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
else
|
|
427
|
+
{
|
|
428
|
+
channelObject.randomPan = false;
|
|
429
|
+
channelObject.controllerChange(midiControllers.pan, panpot);
|
|
430
|
+
}
|
|
431
|
+
break;
|
|
432
|
+
|
|
433
|
+
// chorus send
|
|
434
|
+
case 0x21:
|
|
435
|
+
channelObject.controllerChange(midiControllers.chorusDepth, messageValue);
|
|
436
|
+
break;
|
|
437
|
+
|
|
438
|
+
// reverb send
|
|
439
|
+
case 0x22:
|
|
440
|
+
channelObject.controllerChange(midiControllers.reverbDepth, messageValue);
|
|
441
|
+
break;
|
|
442
|
+
|
|
443
|
+
case 0x40:
|
|
444
|
+
case 0x41:
|
|
445
|
+
case 0x42:
|
|
446
|
+
case 0x43:
|
|
447
|
+
case 0x44:
|
|
448
|
+
case 0x45:
|
|
449
|
+
case 0x46:
|
|
450
|
+
case 0x47:
|
|
451
|
+
case 0x48:
|
|
452
|
+
case 0x49:
|
|
453
|
+
case 0x4A:
|
|
454
|
+
case 0x4B:
|
|
455
|
+
// scale tuning: up to 12 bytes
|
|
456
|
+
const tuningBytes = messageData.length - 9; // data starts at 7, minus checksum and f7
|
|
457
|
+
// read em bytes
|
|
458
|
+
const newTuning = new Int8Array(12);
|
|
459
|
+
for (let i = 0; i < tuningBytes; i++)
|
|
460
|
+
{
|
|
461
|
+
newTuning[i] = messageData[i + 7] - 64;
|
|
462
|
+
}
|
|
463
|
+
channelObject.setOctaveTuning(newTuning);
|
|
464
|
+
const cents = messageValue - 64;
|
|
465
|
+
SpessaSynthInfo(
|
|
466
|
+
`%cChannel %c${channel}%c octave scale tuning. Cents %c${newTuning.join(
|
|
467
|
+
" ")}%c, with %c${arrayToHexString(messageData)}`,
|
|
468
|
+
consoleColors.info,
|
|
469
|
+
consoleColors.recognized,
|
|
470
|
+
consoleColors.info,
|
|
471
|
+
consoleColors.value,
|
|
472
|
+
consoleColors.info,
|
|
473
|
+
consoleColors.value
|
|
474
|
+
);
|
|
475
|
+
channelObject.setTuning(cents);
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
else
|
|
481
|
+
// this is a global system parameter
|
|
482
|
+
if (messageData[5] === 0x00 && messageData[6] === 0x06)
|
|
483
|
+
{
|
|
484
|
+
// roland master pan
|
|
485
|
+
SpessaSynthInfo(
|
|
486
|
+
`%cRoland GS Master Pan set to: %c${messageValue}%c with: %c${arrayToHexString(
|
|
487
|
+
messageData)}`,
|
|
488
|
+
consoleColors.info,
|
|
489
|
+
consoleColors.value,
|
|
490
|
+
consoleColors.info,
|
|
491
|
+
consoleColors.value
|
|
492
|
+
);
|
|
493
|
+
this.setMasterParameter(masterParameterType.masterPan, (messageValue - 64) / 64);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
else if (messageData[5] === 0x00 && messageData[6] === 0x05)
|
|
497
|
+
{
|
|
498
|
+
// roland master key shift (transpose)
|
|
499
|
+
const transpose = messageValue - 64;
|
|
500
|
+
SpessaSynthInfo(
|
|
501
|
+
`%cRoland GS Master Key-Shift set to: %c${transpose}%c with: %c${arrayToHexString(
|
|
502
|
+
messageData)}`,
|
|
503
|
+
consoleColors.info,
|
|
504
|
+
consoleColors.value,
|
|
505
|
+
consoleColors.info,
|
|
506
|
+
consoleColors.value
|
|
507
|
+
);
|
|
508
|
+
this.setMasterTuning(transpose * 100);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
else if (messageData[5] === 0x00 && messageData[6] === 0x04)
|
|
512
|
+
{
|
|
513
|
+
// roland GS master volume
|
|
514
|
+
SpessaSynthInfo(
|
|
515
|
+
`%cRoland GS Master Volume set to: %c${messageValue}%c with: %c${arrayToHexString(
|
|
516
|
+
messageData)}`,
|
|
517
|
+
consoleColors.info,
|
|
518
|
+
consoleColors.value,
|
|
519
|
+
consoleColors.info,
|
|
520
|
+
consoleColors.value
|
|
521
|
+
);
|
|
522
|
+
this.setMIDIVolume(messageValue / 127);
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
// this is some other GS sysex...
|
|
527
|
+
notRecognized();
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
else if (messageData[2] === 0x45 && messageData[3] === 0x12)
|
|
531
|
+
{
|
|
532
|
+
// 0x45: GS Display Data, 0x12: DT1 (Device Transmit)
|
|
533
|
+
// check for embedded copyright
|
|
534
|
+
// (roland SC display sysex) http://www.bandtrax.com.au/sysex.htm
|
|
535
|
+
|
|
536
|
+
if (
|
|
537
|
+
messageData[4] === 0x10 && // Sound Canvas Display
|
|
538
|
+
messageData[6] === 0x00 // Data follows
|
|
539
|
+
)
|
|
540
|
+
{
|
|
541
|
+
if (messageData[5] === 0x00) // Display letters
|
|
542
|
+
{
|
|
543
|
+
// get the text
|
|
544
|
+
// and header ends with (checksum) F7
|
|
545
|
+
const text = new Uint8Array(messageData.slice(7, messageData.length - 2));
|
|
546
|
+
this.callEvent(
|
|
547
|
+
"synthdisplay",
|
|
548
|
+
{
|
|
549
|
+
displayData: text,
|
|
550
|
+
displayType: SynthDisplayType.SoundCanvasText
|
|
551
|
+
}
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
else if (messageData[5] === 0x01) // Matrix display
|
|
555
|
+
{
|
|
556
|
+
// get the data
|
|
557
|
+
// and header ends with (checksum) F7
|
|
558
|
+
const dotMatrixData = new Uint8Array(messageData.slice(7, messageData.length - 3));
|
|
559
|
+
this.callEvent(
|
|
560
|
+
"synthdisplay",
|
|
561
|
+
{
|
|
562
|
+
displayData: dotMatrixData,
|
|
563
|
+
displayType: SynthDisplayType.SoundCanvasDotDisplay
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
SpessaSynthInfo(
|
|
567
|
+
`%cRoland SC Display Dot Matrix via: %c${arrayToHexString(
|
|
568
|
+
messageData)}`,
|
|
569
|
+
consoleColors.info,
|
|
570
|
+
consoleColors.value
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
else
|
|
574
|
+
{
|
|
575
|
+
// this is some other GS sysex...
|
|
576
|
+
notRecognized();
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
else if (messageData[2] === 0x16 && messageData[3] === 0x12 && messageData[4] === 0x10)
|
|
581
|
+
{
|
|
582
|
+
// this is a roland master volume message
|
|
583
|
+
this.setMIDIVolume(messageData[7] / 100);
|
|
584
|
+
SpessaSynthInfo(
|
|
585
|
+
`%cRoland Master Volume control set to: %c${messageData[7]}%c via: %c${arrayToHexString(
|
|
586
|
+
messageData)}`,
|
|
587
|
+
consoleColors.info,
|
|
588
|
+
consoleColors.value,
|
|
589
|
+
consoleColors.info,
|
|
590
|
+
consoleColors.value
|
|
591
|
+
);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
else
|
|
595
|
+
{
|
|
596
|
+
// this is something else...
|
|
597
|
+
SpessaSynthWarn(
|
|
598
|
+
`%cUnrecognized Roland SysEx: %c${arrayToHexString(messageData)}`,
|
|
599
|
+
consoleColors.warn,
|
|
600
|
+
consoleColors.unrecognized
|
|
601
|
+
);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
break;
|
|
605
|
+
|
|
606
|
+
// yamaha
|
|
607
|
+
// http://www.studio4all.de/htmle/main91.html
|
|
608
|
+
case 0x43:
|
|
609
|
+
// XG sysex
|
|
610
|
+
if (messageData[2] === 0x4C)
|
|
611
|
+
{
|
|
612
|
+
// XG system parameter
|
|
613
|
+
if (messageData[3] === 0x00 && messageData[4] === 0x00)
|
|
614
|
+
{
|
|
615
|
+
switch (messageData[5])
|
|
616
|
+
{
|
|
617
|
+
// master volume
|
|
618
|
+
case 0x04:
|
|
619
|
+
const vol = messageData[6];
|
|
620
|
+
this.setMIDIVolume(vol / 127);
|
|
621
|
+
SpessaSynthInfo(
|
|
622
|
+
`%cXG master volume. Volume: %c${vol}`,
|
|
623
|
+
consoleColors.info,
|
|
624
|
+
consoleColors.recognized
|
|
625
|
+
);
|
|
626
|
+
break;
|
|
627
|
+
|
|
628
|
+
// master transpose
|
|
629
|
+
case 0x06:
|
|
630
|
+
const transpose = messageData[6] - 64;
|
|
631
|
+
this.transposeAllChannels(transpose);
|
|
632
|
+
SpessaSynthInfo(
|
|
633
|
+
`%cXG master transpose. Volume: %c${transpose}`,
|
|
634
|
+
consoleColors.info,
|
|
635
|
+
consoleColors.recognized
|
|
636
|
+
);
|
|
637
|
+
break;
|
|
638
|
+
|
|
639
|
+
// XG on
|
|
640
|
+
case 0x7E:
|
|
641
|
+
SpessaSynthInfo("%cXG system on", consoleColors.info);
|
|
642
|
+
this.resetAllControllers(false);
|
|
643
|
+
this.setSystem("xg");
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else
|
|
648
|
+
// XG part parameter
|
|
649
|
+
if (messageData[3] === 0x08)
|
|
650
|
+
{
|
|
651
|
+
if (!isSystemXG(this.system))
|
|
652
|
+
{
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
const channel = messageData[4] + channelOffset;
|
|
656
|
+
if (channel >= this.midiAudioChannels.length)
|
|
657
|
+
{
|
|
658
|
+
// invalid channel
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
const channelObject = this.midiAudioChannels[channel];
|
|
662
|
+
const value = messageData[6];
|
|
663
|
+
switch (messageData[5])
|
|
664
|
+
{
|
|
665
|
+
// bank-select MSB
|
|
666
|
+
case 0x01:
|
|
667
|
+
channelObject.controllerChange(midiControllers.bankSelect, value);
|
|
668
|
+
break;
|
|
669
|
+
|
|
670
|
+
// bank-select LSB
|
|
671
|
+
case 0x02:
|
|
672
|
+
channelObject.controllerChange(midiControllers.lsbForControl0BankSelect, value);
|
|
673
|
+
break;
|
|
674
|
+
|
|
675
|
+
// program change
|
|
676
|
+
case 0x03:
|
|
677
|
+
channelObject.programChange(value);
|
|
678
|
+
break;
|
|
679
|
+
|
|
680
|
+
// note shift
|
|
681
|
+
case 0x08:
|
|
682
|
+
if (channelObject.drumChannel)
|
|
683
|
+
{
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
const semitones = value - 64;
|
|
687
|
+
channelObject.channelTransposeKeyShift = semitones;
|
|
688
|
+
break;
|
|
689
|
+
|
|
690
|
+
// volume
|
|
691
|
+
case 0x0B:
|
|
692
|
+
channelObject.controllerChange(midiControllers.mainVolume, value);
|
|
693
|
+
break;
|
|
694
|
+
|
|
695
|
+
// pan position
|
|
696
|
+
case 0x0E:
|
|
697
|
+
let pan = value;
|
|
698
|
+
if (pan === 0)
|
|
699
|
+
{
|
|
700
|
+
// 0 means random
|
|
701
|
+
channelObject.randomPan = true;
|
|
702
|
+
SpessaSynthInfo(
|
|
703
|
+
`%cRandom pan is set to %cON%c for %c${channel}`,
|
|
704
|
+
consoleColors.info,
|
|
705
|
+
consoleColors.recognized,
|
|
706
|
+
consoleColors.info,
|
|
707
|
+
consoleColors.value
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
else
|
|
711
|
+
{
|
|
712
|
+
channelObject.controllerChange(midiControllers.pan, pan);
|
|
713
|
+
}
|
|
714
|
+
break;
|
|
715
|
+
|
|
716
|
+
// reverb
|
|
717
|
+
case 0x13:
|
|
718
|
+
channelObject.controllerChange(midiControllers.reverbDepth, value);
|
|
719
|
+
break;
|
|
720
|
+
|
|
721
|
+
// chorus
|
|
722
|
+
case 0x12:
|
|
723
|
+
channelObject.controllerChange(midiControllers.chorusDepth, value);
|
|
724
|
+
break;
|
|
725
|
+
|
|
726
|
+
default:
|
|
727
|
+
SpessaSynthWarn(
|
|
728
|
+
`%cUnrecognized Yamaha XG Part Setup: %c${messageData[5].toString(16)
|
|
729
|
+
.toUpperCase()}`,
|
|
730
|
+
consoleColors.warn,
|
|
731
|
+
consoleColors.unrecognized
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
else if (
|
|
736
|
+
messageData[3] === 0x06 && // XG System parameter
|
|
737
|
+
messageData[4] === 0x00 // System Byte
|
|
738
|
+
)
|
|
739
|
+
{
|
|
740
|
+
// displayed letters (remove F7 at the end)
|
|
741
|
+
// include byte 5 as it seems to be line information (useful)
|
|
742
|
+
const textData = new Uint8Array(messageData.slice(5, messageData.length - 1));
|
|
743
|
+
this.callEvent(
|
|
744
|
+
"synthdisplay",
|
|
745
|
+
{
|
|
746
|
+
displayData: textData,
|
|
747
|
+
displayType: SynthDisplayType.XGText
|
|
748
|
+
}
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
else if (isSystemXG(this.system))
|
|
752
|
+
{
|
|
753
|
+
SpessaSynthWarn(
|
|
754
|
+
`%cUnrecognized Yamaha XG SysEx: %c${arrayToHexString(messageData)}`,
|
|
755
|
+
consoleColors.warn,
|
|
756
|
+
consoleColors.unrecognized
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
}
|
|
761
|
+
else
|
|
762
|
+
{
|
|
763
|
+
if (isSystemXG(this.system))
|
|
764
|
+
{
|
|
765
|
+
SpessaSynthWarn(
|
|
766
|
+
`%cUnrecognized Yamaha SysEx: %c${arrayToHexString(messageData)}`,
|
|
767
|
+
consoleColors.warn,
|
|
768
|
+
consoleColors.unrecognized
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
break;
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
}
|
|
776
|
+
}
|