spessasynth_core 3.27.8 → 4.0.0
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 +85 -51
- package/dist/index.d.ts +4057 -0
- package/dist/index.js +17188 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -6
- package/index.js +0 -132
- package/src/externals/README.md +0 -6
- package/src/externals/fflate/LICENSE +0 -21
- package/src/externals/fflate/fflate.min.js +0 -1
- package/src/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
- package/src/externals/stbvorbis_sync/LICENSE +0 -202
- package/src/externals/stbvorbis_sync/NOTICE +0 -6
- package/src/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
- package/src/midi/README.md +0 -32
- package/src/midi/basic_midi.js +0 -587
- package/src/midi/midi_builder.js +0 -203
- package/src/midi/midi_loader.js +0 -321
- package/src/midi/midi_message.js +0 -254
- package/src/midi/midi_sequence.js +0 -230
- package/src/midi/midi_tools/get_note_times.js +0 -154
- package/src/midi/midi_tools/midi_editor.js +0 -611
- package/src/midi/midi_tools/midi_writer.js +0 -105
- package/src/midi/midi_tools/rmidi_writer.js +0 -566
- package/src/midi/midi_tools/used_keys_loaded.js +0 -256
- package/src/midi/xmf_loader.js +0 -454
- package/src/sequencer/README.md +0 -9
- package/src/sequencer/events.js +0 -81
- package/src/sequencer/play.js +0 -362
- package/src/sequencer/process_event.js +0 -165
- package/src/sequencer/process_tick.js +0 -104
- package/src/sequencer/sequencer_engine.js +0 -372
- package/src/sequencer/song_control.js +0 -196
- package/src/soundfont/README.md +0 -11
- package/src/soundfont/basic_soundfont/basic_global_zone.js +0 -6
- package/src/soundfont/basic_soundfont/basic_instrument.js +0 -115
- package/src/soundfont/basic_soundfont/basic_instrument_zone.js +0 -45
- package/src/soundfont/basic_soundfont/basic_preset.js +0 -313
- package/src/soundfont/basic_soundfont/basic_preset_zone.js +0 -39
- package/src/soundfont/basic_soundfont/basic_sample.js +0 -477
- package/src/soundfont/basic_soundfont/basic_soundbank.js +0 -740
- package/src/soundfont/basic_soundfont/basic_zone.js +0 -145
- package/src/soundfont/basic_soundfont/generator.js +0 -76
- package/src/soundfont/basic_soundfont/generator_types.js +0 -151
- package/src/soundfont/basic_soundfont/modulator.js +0 -581
- package/src/soundfont/basic_soundfont/riff_chunk.js +0 -195
- package/src/soundfont/basic_soundfont/write_dls/art2.js +0 -174
- package/src/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
- package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -374
- package/src/soundfont/basic_soundfont/write_dls/ins.js +0 -85
- package/src/soundfont/basic_soundfont/write_dls/lins.js +0 -15
- package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
- package/src/soundfont/basic_soundfont/write_dls/rgn2.js +0 -120
- package/src/soundfont/basic_soundfont/write_dls/wave.js +0 -71
- package/src/soundfont/basic_soundfont/write_dls/write_dls.js +0 -124
- package/src/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
- package/src/soundfont/basic_soundfont/write_dls/wvpl.js +0 -35
- package/src/soundfont/basic_soundfont/write_sf2/ibag.js +0 -60
- package/src/soundfont/basic_soundfont/write_sf2/igen.js +0 -91
- package/src/soundfont/basic_soundfont/write_sf2/imod.js +0 -62
- package/src/soundfont/basic_soundfont/write_sf2/inst.js +0 -42
- package/src/soundfont/basic_soundfont/write_sf2/pbag.js +0 -57
- package/src/soundfont/basic_soundfont/write_sf2/pgen.js +0 -92
- package/src/soundfont/basic_soundfont/write_sf2/phdr.js +0 -61
- package/src/soundfont/basic_soundfont/write_sf2/pmod.js +0 -62
- package/src/soundfont/basic_soundfont/write_sf2/sdta.js +0 -131
- package/src/soundfont/basic_soundfont/write_sf2/shdr.js +0 -77
- package/src/soundfont/basic_soundfont/write_sf2/write.js +0 -287
- package/src/soundfont/dls/articulator_converter.js +0 -402
- package/src/soundfont/dls/dls_destinations.js +0 -38
- package/src/soundfont/dls/dls_instrument.js +0 -20
- package/src/soundfont/dls/dls_preset.js +0 -43
- package/src/soundfont/dls/dls_sample.js +0 -238
- package/src/soundfont/dls/dls_soundfont.js +0 -183
- package/src/soundfont/dls/dls_sources.js +0 -63
- package/src/soundfont/dls/dls_zone.js +0 -89
- package/src/soundfont/dls/read_articulation.js +0 -300
- package/src/soundfont/dls/read_instrument.js +0 -118
- package/src/soundfont/dls/read_instrument_list.js +0 -17
- package/src/soundfont/dls/read_lart.js +0 -35
- package/src/soundfont/dls/read_region.js +0 -157
- package/src/soundfont/dls/read_samples.js +0 -154
- package/src/soundfont/load_soundfont.js +0 -21
- package/src/soundfont/read_sf2/generators.js +0 -43
- package/src/soundfont/read_sf2/instrument_zones.js +0 -75
- package/src/soundfont/read_sf2/instruments.js +0 -71
- package/src/soundfont/read_sf2/modulators.js +0 -25
- package/src/soundfont/read_sf2/preset_zones.js +0 -79
- package/src/soundfont/read_sf2/presets.js +0 -80
- package/src/soundfont/read_sf2/samples.js +0 -317
- package/src/soundfont/read_sf2/soundfont.js +0 -452
- package/src/soundfont/read_sf2/zones.js +0 -28
- package/src/synthetizer/README.md +0 -7
- package/src/synthetizer/audio_engine/README.md +0 -9
- package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -289
- package/src/synthetizer/audio_engine/engine_components/controller_tables.js +0 -90
- package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +0 -95
- package/src/synthetizer/audio_engine/engine_components/enums.js +0 -18
- package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -151
- package/src/synthetizer/audio_engine/engine_components/lfo.js +0 -26
- package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -551
- package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
- package/src/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
- package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -265
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -124
- package/src/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
- package/src/synthetizer/audio_engine/engine_components/voice.js +0 -525
- package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -402
- package/src/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -274
- package/src/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -159
- package/src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -53
- package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -254
- package/src/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -20
- package/src/synthetizer/audio_engine/engine_methods/data_entry/awe32.js +0 -198
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -281
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -109
- package/src/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
- package/src/synthetizer/audio_engine/engine_methods/note_on.js +0 -220
- package/src/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
- package/src/synthetizer/audio_engine/engine_methods/program_change.js +0 -35
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +0 -214
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/embedded_sound_bank.js +0 -42
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/update_preset_list.js +0 -19
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -23
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -56
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
- package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -1058
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -23
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -31
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -29
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -26
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
- package/src/synthetizer/audio_engine/main_processor.js +0 -817
- package/src/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -16
- package/src/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
- package/src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -116
- package/src/synthetizer/audio_engine/synth_processor_options.js +0 -18
- package/src/synthetizer/synth_constants.js +0 -26
- package/src/utils/README.md +0 -8
- package/src/utils/buffer_to_wav.js +0 -197
- package/src/utils/byte_functions/big_endian.js +0 -32
- package/src/utils/byte_functions/little_endian.js +0 -77
- package/src/utils/byte_functions/string.js +0 -92
- package/src/utils/byte_functions/variable_length_quantity.js +0 -42
- package/src/utils/fill_with_defaults.js +0 -21
- package/src/utils/indexed_array.js +0 -34
- package/src/utils/loggin.js +0 -71
- package/src/utils/other.js +0 -92
- package/src/utils/sysex_detector.js +0 -58
- package/src/utils/xg_hacks.js +0 -193
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { midiControllers } from "../../../../midi/midi_message.js";
|
|
2
|
-
import { channelConfiguration, customControllers, dataEntryStates } from "../../engine_components/controller_tables.js";
|
|
3
|
-
import { nonRegisteredMSB } from "../data_entry/data_entry_coarse.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param controllerNumber {number}
|
|
7
|
-
* @param controllerValue {number}
|
|
8
|
-
* @param force {boolean}
|
|
9
|
-
* @this {MidiAudioChannel}
|
|
10
|
-
*/
|
|
11
|
-
export function controllerChange(controllerNumber, controllerValue, force = false)
|
|
12
|
-
{
|
|
13
|
-
if (controllerNumber > 127)
|
|
14
|
-
{
|
|
15
|
-
// channel configuration. force must be set to true
|
|
16
|
-
if (!force)
|
|
17
|
-
{
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
switch (controllerNumber)
|
|
21
|
-
{
|
|
22
|
-
default:
|
|
23
|
-
return;
|
|
24
|
-
|
|
25
|
-
case channelConfiguration.velocityOverride:
|
|
26
|
-
this.velocityOverride = controllerValue;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// lsb controller values: append them as the lower nibble of the 14-bit value
|
|
31
|
-
// excluding bank select and data entry as it's handled separately
|
|
32
|
-
if (
|
|
33
|
-
controllerNumber >= midiControllers.lsbForControl1ModulationWheel
|
|
34
|
-
&& controllerNumber <= midiControllers.lsbForControl13EffectControl2
|
|
35
|
-
&& controllerNumber !== midiControllers.lsbForControl6DataEntry
|
|
36
|
-
)
|
|
37
|
-
{
|
|
38
|
-
const actualCCNum = controllerNumber - 32;
|
|
39
|
-
if (this.lockedControllers[actualCCNum])
|
|
40
|
-
{
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
// append the lower nibble to the main controller
|
|
44
|
-
this.midiControllers[actualCCNum] = (this.midiControllers[actualCCNum] & 0x3F80) | (controllerValue & 0x7F);
|
|
45
|
-
this.voices.forEach(v => this.computeModulators(v, 1, actualCCNum));
|
|
46
|
-
}
|
|
47
|
-
if (this.lockedControllers[controllerNumber])
|
|
48
|
-
{
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// apply the cc to the table
|
|
53
|
-
this.midiControllers[controllerNumber] = controllerValue << 7;
|
|
54
|
-
|
|
55
|
-
// interpret special CCs
|
|
56
|
-
{
|
|
57
|
-
switch (controllerNumber)
|
|
58
|
-
{
|
|
59
|
-
case midiControllers.allNotesOff:
|
|
60
|
-
this.stopAllNotes();
|
|
61
|
-
break;
|
|
62
|
-
|
|
63
|
-
case midiControllers.allSoundOff:
|
|
64
|
-
this.stopAllNotes(true);
|
|
65
|
-
break;
|
|
66
|
-
|
|
67
|
-
// special case: bank select
|
|
68
|
-
case midiControllers.bankSelect:
|
|
69
|
-
this.setBankSelect(controllerValue);
|
|
70
|
-
break;
|
|
71
|
-
|
|
72
|
-
case midiControllers.lsbForControl0BankSelect:
|
|
73
|
-
this.setBankSelect(controllerValue, true);
|
|
74
|
-
break;
|
|
75
|
-
|
|
76
|
-
// check for RPN and NPRN and data entry
|
|
77
|
-
case midiControllers.RPNLsb:
|
|
78
|
-
this.dataEntryState = dataEntryStates.RPFine;
|
|
79
|
-
break;
|
|
80
|
-
|
|
81
|
-
case midiControllers.RPNMsb:
|
|
82
|
-
this.dataEntryState = dataEntryStates.RPCoarse;
|
|
83
|
-
break;
|
|
84
|
-
|
|
85
|
-
case midiControllers.NRPNMsb:
|
|
86
|
-
// sfspec section 9.6.2
|
|
87
|
-
this.customControllers[customControllers.sf2NPRNGeneratorLSB] = 0;
|
|
88
|
-
this.dataEntryState = dataEntryStates.NRPCoarse;
|
|
89
|
-
break;
|
|
90
|
-
|
|
91
|
-
case midiControllers.NRPNLsb:
|
|
92
|
-
if (this.midiControllers[midiControllers.NRPNMsb] >> 7 === nonRegisteredMSB.SF2)
|
|
93
|
-
{
|
|
94
|
-
// if a <100 value has already been sent, reset!
|
|
95
|
-
if (this.customControllers[customControllers.sf2NPRNGeneratorLSB] % 100 !== 0)
|
|
96
|
-
{
|
|
97
|
-
this.customControllers[customControllers.sf2NPRNGeneratorLSB] = 0;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (controllerValue === 100)
|
|
101
|
-
{
|
|
102
|
-
this.customControllers[customControllers.sf2NPRNGeneratorLSB] += 100;
|
|
103
|
-
}
|
|
104
|
-
else if (controllerValue === 101)
|
|
105
|
-
{
|
|
106
|
-
this.customControllers[customControllers.sf2NPRNGeneratorLSB] += 1000;
|
|
107
|
-
}
|
|
108
|
-
else if (controllerValue === 102)
|
|
109
|
-
{
|
|
110
|
-
this.customControllers[customControllers.sf2NPRNGeneratorLSB] += 10000;
|
|
111
|
-
}
|
|
112
|
-
else if (controllerValue < 100)
|
|
113
|
-
{
|
|
114
|
-
this.customControllers[customControllers.sf2NPRNGeneratorLSB] += controllerValue;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
this.dataEntryState = dataEntryStates.NRPFine;
|
|
118
|
-
break;
|
|
119
|
-
|
|
120
|
-
case midiControllers.dataEntryMsb:
|
|
121
|
-
this.dataEntryCoarse(controllerValue);
|
|
122
|
-
break;
|
|
123
|
-
|
|
124
|
-
case midiControllers.lsbForControl6DataEntry:
|
|
125
|
-
this.dataEntryFine(controllerValue);
|
|
126
|
-
break;
|
|
127
|
-
|
|
128
|
-
case midiControllers.resetAllControllers:
|
|
129
|
-
this.resetControllersRP15Compliant();
|
|
130
|
-
break;
|
|
131
|
-
|
|
132
|
-
case midiControllers.sustainPedal:
|
|
133
|
-
if (controllerValue >= 64)
|
|
134
|
-
{
|
|
135
|
-
this.holdPedal = true;
|
|
136
|
-
}
|
|
137
|
-
else
|
|
138
|
-
{
|
|
139
|
-
this.holdPedal = false;
|
|
140
|
-
this.sustainedVoices.forEach(v =>
|
|
141
|
-
{
|
|
142
|
-
v.release(this.synth.currentSynthTime);
|
|
143
|
-
});
|
|
144
|
-
this.sustainedVoices = [];
|
|
145
|
-
}
|
|
146
|
-
break;
|
|
147
|
-
|
|
148
|
-
// default: just compute modulators
|
|
149
|
-
default:
|
|
150
|
-
this.voices.forEach(v => this.computeModulators(v, 1, controllerNumber));
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
this.synth.callEvent("controllerchange", {
|
|
155
|
-
channel: this.channelNumber,
|
|
156
|
-
controllerNumber: controllerNumber,
|
|
157
|
-
controllerValue: controllerValue
|
|
158
|
-
});
|
|
159
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { SYNTHESIZER_GAIN } from "../../main_processor.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @enum {number}
|
|
5
|
-
*/
|
|
6
|
-
export const masterParameterType = {
|
|
7
|
-
mainVolume: 0,
|
|
8
|
-
masterPan: 1,
|
|
9
|
-
voicesCap: 2,
|
|
10
|
-
interpolationType: 3,
|
|
11
|
-
midiSystem: 4,
|
|
12
|
-
monophonicRetriggerMode: 5
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @this {SpessaSynthProcessor}
|
|
17
|
-
* @param type {masterParameterType}
|
|
18
|
-
* @param value {number|string|interpolationTypes}
|
|
19
|
-
*/
|
|
20
|
-
export function setMasterParameter(type, value)
|
|
21
|
-
{
|
|
22
|
-
switch (type)
|
|
23
|
-
{
|
|
24
|
-
case masterParameterType.masterPan:
|
|
25
|
-
let pan = value;
|
|
26
|
-
this.pan = pan;
|
|
27
|
-
// clamp to 0-1 (0 is left)
|
|
28
|
-
pan = (pan / 2) + 0.5;
|
|
29
|
-
this.panLeft = (1 - pan);
|
|
30
|
-
this.panRight = (pan);
|
|
31
|
-
break;
|
|
32
|
-
|
|
33
|
-
case masterParameterType.mainVolume:
|
|
34
|
-
this.masterGain = value * SYNTHESIZER_GAIN;
|
|
35
|
-
break;
|
|
36
|
-
|
|
37
|
-
case masterParameterType.voicesCap:
|
|
38
|
-
this.voiceCap = value;
|
|
39
|
-
break;
|
|
40
|
-
|
|
41
|
-
case masterParameterType.interpolationType:
|
|
42
|
-
this.interpolationType = value;
|
|
43
|
-
break;
|
|
44
|
-
|
|
45
|
-
case masterParameterType.midiSystem:
|
|
46
|
-
this.setSystem(value);
|
|
47
|
-
break;
|
|
48
|
-
|
|
49
|
-
case masterParameterType.monophonicRetriggerMode:
|
|
50
|
-
this._monophonicRetriggerMode = true;
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import { consoleColors } from "../../../../utils/other.js";
|
|
2
|
-
import { SpessaSynthInfo } from "../../../../utils/loggin.js";
|
|
3
|
-
import { modulatorSources } from "../../../../soundfont/basic_soundfont/modulator.js";
|
|
4
|
-
import {
|
|
5
|
-
customControllers,
|
|
6
|
-
customResetArray,
|
|
7
|
-
dataEntryStates,
|
|
8
|
-
NON_CC_INDEX_OFFSET,
|
|
9
|
-
PORTAMENTO_CONTROL_UNSET,
|
|
10
|
-
resetArray
|
|
11
|
-
} from "../../engine_components/controller_tables.js";
|
|
12
|
-
import { midiControllers } from "../../../../midi/midi_message.js";
|
|
13
|
-
import { DEFAULT_PERCUSSION, DEFAULT_SYNTH_MODE } from "../../../synth_constants.js";
|
|
14
|
-
import { getDefaultBank } from "../../../../utils/xg_hacks.js";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Full system reset
|
|
19
|
-
* @this {SpessaSynthProcessor}
|
|
20
|
-
* @param log {boolean}
|
|
21
|
-
*/
|
|
22
|
-
export function resetAllControllers(log = true)
|
|
23
|
-
{
|
|
24
|
-
if (log)
|
|
25
|
-
{
|
|
26
|
-
SpessaSynthInfo("%cResetting all controllers!", consoleColors.info);
|
|
27
|
-
}
|
|
28
|
-
this.callEvent("allcontrollerreset", undefined);
|
|
29
|
-
this.setSystem(DEFAULT_SYNTH_MODE);
|
|
30
|
-
for (let channelNumber = 0; channelNumber < this.midiAudioChannels.length; channelNumber++)
|
|
31
|
-
{
|
|
32
|
-
/**
|
|
33
|
-
* @type {MidiAudioChannel}
|
|
34
|
-
**/
|
|
35
|
-
const ch = this.midiAudioChannels[channelNumber];
|
|
36
|
-
|
|
37
|
-
ch.resetControllers();
|
|
38
|
-
// if preset is unlocked, switch to non-drums and call event
|
|
39
|
-
if (!ch.lockPreset)
|
|
40
|
-
{
|
|
41
|
-
ch.setBankSelect(getDefaultBank(this.system));
|
|
42
|
-
if (channelNumber % 16 === DEFAULT_PERCUSSION)
|
|
43
|
-
{
|
|
44
|
-
ch.setPreset(this.drumPreset);
|
|
45
|
-
ch.drumChannel = true;
|
|
46
|
-
this.callEvent("drumchange", {
|
|
47
|
-
channel: channelNumber,
|
|
48
|
-
isDrumChannel: true
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
else
|
|
52
|
-
{
|
|
53
|
-
ch.drumChannel = false;
|
|
54
|
-
ch.setPreset(this.defaultPreset);
|
|
55
|
-
this.callEvent("drumchange", {
|
|
56
|
-
channel: channelNumber,
|
|
57
|
-
isDrumChannel: false
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else
|
|
62
|
-
{
|
|
63
|
-
this.callEvent("drumchange", {
|
|
64
|
-
channel: channelNumber,
|
|
65
|
-
isDrumChannel: ch.drumChannel
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
// safety net
|
|
69
|
-
if (!ch.preset)
|
|
70
|
-
{
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
const presetBank = ch.preset?.bank;
|
|
74
|
-
// call program change
|
|
75
|
-
this.callEvent("programchange", {
|
|
76
|
-
channel: channelNumber,
|
|
77
|
-
program: ch.preset?.program,
|
|
78
|
-
bank: presetBank
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
for (let ccNum = 0; ccNum < 128; ccNum++)
|
|
82
|
-
{
|
|
83
|
-
if (this.midiAudioChannels[channelNumber].lockedControllers[ccNum])
|
|
84
|
-
{
|
|
85
|
-
// was not reset so restore the value
|
|
86
|
-
this.callEvent("controllerchange", {
|
|
87
|
-
channel: channelNumber,
|
|
88
|
-
controllerNumber: ccNum,
|
|
89
|
-
controllerValue: this.midiAudioChannels[channelNumber].midiControllers[ccNum] >> 7
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
// restore pitch wheel
|
|
97
|
-
if (this.midiAudioChannels[channelNumber].lockedControllers[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheel] === false)
|
|
98
|
-
{
|
|
99
|
-
const val = this.midiAudioChannels[channelNumber].midiControllers[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheel];
|
|
100
|
-
const msb = val >> 7;
|
|
101
|
-
const lsb = val & 0x7F;
|
|
102
|
-
this.callEvent("pitchwheel", {
|
|
103
|
-
channel: channelNumber,
|
|
104
|
-
MSB: msb,
|
|
105
|
-
LSB: lsb
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// restore channel pressure
|
|
110
|
-
if (this.midiAudioChannels[channelNumber].lockedControllers[NON_CC_INDEX_OFFSET + modulatorSources.channelPressure] === false)
|
|
111
|
-
{
|
|
112
|
-
const val = this.midiAudioChannels[channelNumber].midiControllers[NON_CC_INDEX_OFFSET + modulatorSources.channelPressure] >> 7;
|
|
113
|
-
this.callEvent("channelpressure", {
|
|
114
|
-
channel: channelNumber,
|
|
115
|
-
pressure: val
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
this.tunings = [];
|
|
120
|
-
this.tunings = [];
|
|
121
|
-
for (let i = 0; i < 128; i++)
|
|
122
|
-
{
|
|
123
|
-
this.tunings.push([]);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
this.setMIDIVolume(1);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Resets all controllers for channel
|
|
131
|
-
* @this {MidiAudioChannel}
|
|
132
|
-
*/
|
|
133
|
-
export function resetControllers()
|
|
134
|
-
{
|
|
135
|
-
this.channelOctaveTuning.fill(0);
|
|
136
|
-
|
|
137
|
-
// reset the array
|
|
138
|
-
for (let i = 0; i < resetArray.length; i++)
|
|
139
|
-
{
|
|
140
|
-
if (this.lockedControllers[i])
|
|
141
|
-
{
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
const resetValue = resetArray[i];
|
|
145
|
-
if (this.midiControllers[i] !== resetValue && i < 127)
|
|
146
|
-
{
|
|
147
|
-
if (i === midiControllers.portamentoControl)
|
|
148
|
-
{
|
|
149
|
-
this.midiControllers[i] = PORTAMENTO_CONTROL_UNSET;
|
|
150
|
-
}
|
|
151
|
-
else
|
|
152
|
-
{
|
|
153
|
-
this.controllerChange(i, resetValue >> 7);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
else
|
|
157
|
-
{
|
|
158
|
-
// out of range, do a regular reset
|
|
159
|
-
this.midiControllers[i] = resetValue;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
this.channelVibrato = { rate: 0, depth: 0, delay: 0 };
|
|
163
|
-
this.holdPedal = false;
|
|
164
|
-
this.randomPan = false;
|
|
165
|
-
|
|
166
|
-
this.sysExModulators.resetModulators();
|
|
167
|
-
|
|
168
|
-
// reset custom controllers
|
|
169
|
-
// special case: transpose does not get affected
|
|
170
|
-
const transpose = this.customControllers[customControllers.channelTransposeFine];
|
|
171
|
-
this.customControllers.set(customResetArray);
|
|
172
|
-
this.setCustomController(customControllers.channelTransposeFine, transpose);
|
|
173
|
-
this.resetParameters();
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* @type {Set<midiControllers|number>}
|
|
180
|
-
*/
|
|
181
|
-
export const nonResetableCCs = new Set([
|
|
182
|
-
midiControllers.bankSelect,
|
|
183
|
-
midiControllers.lsbForControl0BankSelect,
|
|
184
|
-
midiControllers.mainVolume,
|
|
185
|
-
midiControllers.lsbForControl7MainVolume,
|
|
186
|
-
midiControllers.pan,
|
|
187
|
-
midiControllers.lsbForControl10Pan,
|
|
188
|
-
midiControllers.reverbDepth,
|
|
189
|
-
midiControllers.tremoloDepth,
|
|
190
|
-
midiControllers.chorusDepth,
|
|
191
|
-
midiControllers.detuneDepth,
|
|
192
|
-
midiControllers.phaserDepth,
|
|
193
|
-
midiControllers.soundVariation,
|
|
194
|
-
midiControllers.filterResonance,
|
|
195
|
-
midiControllers.releaseTime,
|
|
196
|
-
midiControllers.attackTime,
|
|
197
|
-
midiControllers.brightness,
|
|
198
|
-
midiControllers.decayTime,
|
|
199
|
-
midiControllers.vibratoRate,
|
|
200
|
-
midiControllers.vibratoDepth,
|
|
201
|
-
midiControllers.vibratoDelay,
|
|
202
|
-
midiControllers.soundController10
|
|
203
|
-
]);
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Reset all controllers for channel, but RP-15 compliant
|
|
207
|
-
* https://amei.or.jp/midistandardcommittee/Recommended_Practice/e/rp15.pdf
|
|
208
|
-
* @this {MidiAudioChannel}
|
|
209
|
-
*/
|
|
210
|
-
export function resetControllersRP15Compliant()
|
|
211
|
-
{
|
|
212
|
-
// reset tunings
|
|
213
|
-
this.channelOctaveTuning.fill(0);
|
|
214
|
-
|
|
215
|
-
// reset pitch bend
|
|
216
|
-
this.pitchWheel(64, 0);
|
|
217
|
-
|
|
218
|
-
this.channelVibrato = { rate: 0, depth: 0, delay: 0 };
|
|
219
|
-
|
|
220
|
-
for (let i = 0; i < 128; i++)
|
|
221
|
-
{
|
|
222
|
-
const resetValue = resetArray[i];
|
|
223
|
-
if (!nonResetableCCs.has(i) && resetValue !== this.midiControllers[i])
|
|
224
|
-
{
|
|
225
|
-
if (i === midiControllers.portamentoControl)
|
|
226
|
-
{
|
|
227
|
-
this.midiControllers[i] = PORTAMENTO_CONTROL_UNSET;
|
|
228
|
-
}
|
|
229
|
-
else
|
|
230
|
-
{
|
|
231
|
-
this.controllerChange(i, resetValue >> 7);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
this.resetGeneratorOverrides();
|
|
236
|
-
this.resetGeneratorOffsets();
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* @this {MidiAudioChannel}
|
|
241
|
-
*/
|
|
242
|
-
export function resetParameters()
|
|
243
|
-
{
|
|
244
|
-
/**
|
|
245
|
-
* reset the state machine to idle
|
|
246
|
-
*/
|
|
247
|
-
this.dataEntryState = dataEntryStates.Idle;
|
|
248
|
-
this.midiControllers[midiControllers.NRPNLsb] = 127 << 7;
|
|
249
|
-
this.midiControllers[midiControllers.NRPNMsb] = 127 << 7;
|
|
250
|
-
this.midiControllers[midiControllers.RPNLsb] = 127 << 7;
|
|
251
|
-
this.midiControllers[midiControllers.RPNMsb] = 127 << 7;
|
|
252
|
-
this.resetGeneratorOverrides();
|
|
253
|
-
this.resetGeneratorOffsets();
|
|
254
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { MidiAudioChannel } from "../engine_components/midi_audio_channel.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @param sendEvent {boolean}
|
|
5
|
-
* @this {SpessaSynthProcessor}
|
|
6
|
-
*/
|
|
7
|
-
export function createMidiChannel(sendEvent = false)
|
|
8
|
-
{
|
|
9
|
-
/**
|
|
10
|
-
* @type {MidiAudioChannel}
|
|
11
|
-
*/
|
|
12
|
-
const channel = new MidiAudioChannel(this, this.defaultPreset, this.midiAudioChannels.length);
|
|
13
|
-
this.midiAudioChannels.push(channel);
|
|
14
|
-
if (sendEvent)
|
|
15
|
-
{
|
|
16
|
-
this.callEvent("newchannel", undefined);
|
|
17
|
-
channel.sendChannelProperty();
|
|
18
|
-
this.midiAudioChannels[this.midiAudioChannels.length - 1].setDrums(true);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { SpessaSynthWarn } from "../../../../utils/loggin.js";
|
|
2
|
-
import { consoleColors } from "../../../../utils/other.js";
|
|
3
|
-
import { generatorTypes } from "../../../../soundfont/basic_soundfont/generator_types.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* http://archive.gamedev.net/archive/reference/articles/article445.html
|
|
7
|
-
* https://github.com/user-attachments/files/15757220/adip301.pdf
|
|
8
|
-
* @type {generatorTypes[]}
|
|
9
|
-
*/
|
|
10
|
-
const AWE_NRPN_GENERATOR_MAPPINGS = [
|
|
11
|
-
generatorTypes.delayModLFO,
|
|
12
|
-
generatorTypes.freqModLFO,
|
|
13
|
-
|
|
14
|
-
generatorTypes.delayVibLFO,
|
|
15
|
-
generatorTypes.freqVibLFO,
|
|
16
|
-
|
|
17
|
-
generatorTypes.delayModEnv,
|
|
18
|
-
generatorTypes.attackModEnv,
|
|
19
|
-
generatorTypes.holdModEnv,
|
|
20
|
-
generatorTypes.decayModEnv,
|
|
21
|
-
generatorTypes.sustainModEnv,
|
|
22
|
-
generatorTypes.releaseModEnv,
|
|
23
|
-
|
|
24
|
-
generatorTypes.delayVolEnv,
|
|
25
|
-
generatorTypes.attackVolEnv,
|
|
26
|
-
generatorTypes.holdVolEnv,
|
|
27
|
-
generatorTypes.decayVolEnv,
|
|
28
|
-
generatorTypes.sustainVolEnv,
|
|
29
|
-
generatorTypes.releaseVolEnv,
|
|
30
|
-
|
|
31
|
-
generatorTypes.fineTune,
|
|
32
|
-
|
|
33
|
-
generatorTypes.modLfoToPitch,
|
|
34
|
-
generatorTypes.vibLfoToPitch,
|
|
35
|
-
generatorTypes.modEnvToPitch,
|
|
36
|
-
generatorTypes.modLfoToVolume,
|
|
37
|
-
|
|
38
|
-
generatorTypes.initialFilterFc,
|
|
39
|
-
generatorTypes.initialFilterQ,
|
|
40
|
-
|
|
41
|
-
generatorTypes.modLfoToFilterFc,
|
|
42
|
-
generatorTypes.modEnvToFilterFc,
|
|
43
|
-
|
|
44
|
-
generatorTypes.chorusEffectsSend,
|
|
45
|
-
generatorTypes.reverbEffectsSend
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Function that emulates AWE32 similarly to fluidsynth
|
|
50
|
-
* https://github.com/FluidSynth/fluidsynth/wiki/FluidFeatures
|
|
51
|
-
*
|
|
52
|
-
* Note: This makes use of findings by mrbumpy409:
|
|
53
|
-
* https://github.com/fluidSynth/fluidsynth/issues/1473
|
|
54
|
-
*
|
|
55
|
-
* The excellent test files are available here, also collected and converted by mrbumpy409:
|
|
56
|
-
* https://github.com/mrbumpy409/AWE32-midi-conversions
|
|
57
|
-
* @this {MidiAudioChannel}
|
|
58
|
-
* @param aweGen {number}
|
|
59
|
-
* @param dataLSB {number}
|
|
60
|
-
* @param dataMSB {number}
|
|
61
|
-
*/
|
|
62
|
-
export function handleAWE32NRPN(aweGen, dataLSB, dataMSB)
|
|
63
|
-
{
|
|
64
|
-
const clip = (v, min, max) => Math.max(min, Math.min(max, v));
|
|
65
|
-
const msecToTimecents = ms => Math.max(-32768, 1200 * Math.log2(ms / 1000));
|
|
66
|
-
const hzToCents = hz => 6900 + 1200 * Math.log2(hz / 440);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
let dataValue = (dataMSB << 7) | dataLSB;
|
|
70
|
-
// center the value
|
|
71
|
-
// though ranges reported as 0 to 127 only use LSB
|
|
72
|
-
dataValue -= 8192;
|
|
73
|
-
const generator = AWE_NRPN_GENERATOR_MAPPINGS[aweGen];
|
|
74
|
-
if (!generator)
|
|
75
|
-
{
|
|
76
|
-
SpessaSynthWarn(
|
|
77
|
-
`Invalid AWE32 LSB: %c${aweGen}`,
|
|
78
|
-
consoleColors.unrecognized
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
let milliseconds, hertz, centibels, cents;
|
|
82
|
-
switch (generator)
|
|
83
|
-
{
|
|
84
|
-
default:
|
|
85
|
-
// this should not happen
|
|
86
|
-
break;
|
|
87
|
-
|
|
88
|
-
// delays
|
|
89
|
-
case generatorTypes.delayModLFO:
|
|
90
|
-
case generatorTypes.delayVibLFO:
|
|
91
|
-
case generatorTypes.delayVolEnv:
|
|
92
|
-
case generatorTypes.delayModEnv:
|
|
93
|
-
milliseconds = 4 * clip(dataValue, 0, 5900);
|
|
94
|
-
// convert to timecents
|
|
95
|
-
this.setGeneratorOverride(generator, msecToTimecents(milliseconds));
|
|
96
|
-
break;
|
|
97
|
-
|
|
98
|
-
// attacks
|
|
99
|
-
case generatorTypes.attackVolEnv:
|
|
100
|
-
case generatorTypes.attackModEnv:
|
|
101
|
-
milliseconds = clip(dataValue, 0, 5940);
|
|
102
|
-
// convert to timecents
|
|
103
|
-
this.setGeneratorOverride(generator, msecToTimecents(milliseconds));
|
|
104
|
-
break;
|
|
105
|
-
|
|
106
|
-
// holds
|
|
107
|
-
case generatorTypes.holdVolEnv:
|
|
108
|
-
case generatorTypes.holdModEnv:
|
|
109
|
-
milliseconds = clip(dataValue, 0, 8191);
|
|
110
|
-
// convert to timecents
|
|
111
|
-
this.setGeneratorOverride(generator, msecToTimecents(milliseconds));
|
|
112
|
-
break;
|
|
113
|
-
|
|
114
|
-
// decays and releases (share clips and units)
|
|
115
|
-
case generatorTypes.decayModEnv:
|
|
116
|
-
case generatorTypes.decayVolEnv:
|
|
117
|
-
case generatorTypes.releaseVolEnv:
|
|
118
|
-
case generatorTypes.releaseModEnv:
|
|
119
|
-
milliseconds = 4 * clip(dataValue, 0, 5940);
|
|
120
|
-
// convert to timecents
|
|
121
|
-
this.setGeneratorOverride(generator, msecToTimecents(milliseconds));
|
|
122
|
-
break;
|
|
123
|
-
|
|
124
|
-
// lfo frequencies
|
|
125
|
-
case generatorTypes.freqVibLFO:
|
|
126
|
-
case generatorTypes.freqModLFO:
|
|
127
|
-
hertz = 0.084 * dataLSB;
|
|
128
|
-
// convert to abs cents
|
|
129
|
-
this.setGeneratorOverride(generator, hzToCents(hertz), true);
|
|
130
|
-
break;
|
|
131
|
-
|
|
132
|
-
// sustains
|
|
133
|
-
case generatorTypes.sustainVolEnv:
|
|
134
|
-
case generatorTypes.sustainModEnv:
|
|
135
|
-
// 0.75 dB is 7.5 cB
|
|
136
|
-
centibels = dataLSB * 7.5;
|
|
137
|
-
this.setGeneratorOverride(generator, centibels);
|
|
138
|
-
break;
|
|
139
|
-
|
|
140
|
-
// pitch
|
|
141
|
-
case generatorTypes.fineTune:
|
|
142
|
-
// data is already centered
|
|
143
|
-
this.setGeneratorOverride(generator, dataValue, true);
|
|
144
|
-
break;
|
|
145
|
-
|
|
146
|
-
// lfo to pitch
|
|
147
|
-
case generatorTypes.modLfoToPitch:
|
|
148
|
-
case generatorTypes.vibLfoToPitch:
|
|
149
|
-
cents = clip(dataValue, -127, 127) * 9.375;
|
|
150
|
-
this.setGeneratorOverride(generator, cents, true);
|
|
151
|
-
break;
|
|
152
|
-
|
|
153
|
-
// env to pitch
|
|
154
|
-
case generatorTypes.modEnvToPitch:
|
|
155
|
-
cents = clip(dataValue, -127, 127) * 9.375;
|
|
156
|
-
this.setGeneratorOverride(generator, cents);
|
|
157
|
-
break;
|
|
158
|
-
|
|
159
|
-
// mod lfo to vol
|
|
160
|
-
case generatorTypes.modLfoToVolume:
|
|
161
|
-
// 0.1875 dB is 1.875 cB
|
|
162
|
-
centibels = 1.875 * dataLSB;
|
|
163
|
-
this.setGeneratorOverride(generator, centibels, true);
|
|
164
|
-
break;
|
|
165
|
-
|
|
166
|
-
// filter fc
|
|
167
|
-
case generatorTypes.initialFilterFc:
|
|
168
|
-
// minimum: 100 Hz -> 4335 cents
|
|
169
|
-
const fcCents = 4335 + 59 * dataLSB;
|
|
170
|
-
this.setGeneratorOverride(generator, fcCents, true);
|
|
171
|
-
break;
|
|
172
|
-
|
|
173
|
-
// filter Q
|
|
174
|
-
case generatorTypes.initialFilterQ:
|
|
175
|
-
// note: this uses the "modulator-ish" approach proposed by mrbumpy409
|
|
176
|
-
// here https://github.com/FluidSynth/fluidsynth/issues/1473
|
|
177
|
-
centibels = 215 * (dataLSB / 127);
|
|
178
|
-
this.setGeneratorOverride(generator, centibels, true);
|
|
179
|
-
break;
|
|
180
|
-
|
|
181
|
-
// to filterFc
|
|
182
|
-
case generatorTypes.modLfoToFilterFc:
|
|
183
|
-
cents = clip(dataValue, -64, 63) * 56.25;
|
|
184
|
-
this.setGeneratorOverride(generator, cents, true);
|
|
185
|
-
break;
|
|
186
|
-
|
|
187
|
-
case generatorTypes.modEnvToFilterFc:
|
|
188
|
-
cents = clip(dataValue, -64, 63) * 56.25;
|
|
189
|
-
this.setGeneratorOverride(generator, cents);
|
|
190
|
-
break;
|
|
191
|
-
|
|
192
|
-
// effects
|
|
193
|
-
case generatorTypes.chorusEffectsSend:
|
|
194
|
-
case generatorTypes.reverbEffectsSend:
|
|
195
|
-
this.setGeneratorOverride(generator, clip(dataValue, 0, 255) * (1000 / 255));
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
}
|