spessasynth_core 1.1.3 → 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 -313
- 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 -223
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +0 -133
- 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 -272
- 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 -175
- 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 -285
- 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,222 @@
|
|
|
1
|
+
import { combineArrays, IndexedByteArray } from "../../../utils/indexed_array.js";
|
|
2
|
+
import { RiffChunk, writeRIFFChunk } from "../riff_chunk.js";
|
|
3
|
+
import { writeStringAsBytes } from "../../../utils/byte_functions/string.js";
|
|
4
|
+
import { consoleColors } from "../../../utils/other.js";
|
|
5
|
+
import { getIGEN } from "./igen.js";
|
|
6
|
+
import { getSDTA } from "./sdta.js";
|
|
7
|
+
import { getSHDR } from "./shdr.js";
|
|
8
|
+
import { getIMOD } from "./imod.js";
|
|
9
|
+
import { getIBAG } from "./ibag.js";
|
|
10
|
+
import { getINST } from "./inst.js";
|
|
11
|
+
import { getPGEN } from "./pgen.js";
|
|
12
|
+
import { getPMOD } from "./pmod.js";
|
|
13
|
+
import { getPBAG } from "./pbag.js";
|
|
14
|
+
import { getPHDR } from "./phdr.js";
|
|
15
|
+
import { writeWord } from "../../../utils/byte_functions/little_endian.js";
|
|
16
|
+
import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd, SpessaSynthInfo } from "../../../utils/loggin.js";
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} SoundFont2WriteOptions
|
|
19
|
+
* @property {boolean} compress - if the soundfont should be compressed with the Ogg Vorbis codec
|
|
20
|
+
* @property {number} compressionQuality - the vorbis compression quality, from -0.1 to 1
|
|
21
|
+
* @property {EncodeVorbisFunction|undefined} compressionFunction - the encode vorbis function.
|
|
22
|
+
* Can be undefined if not compressed.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @type {SoundFont2WriteOptions}
|
|
27
|
+
*/
|
|
28
|
+
const DEFAULT_WRITE_OPTIONS = {
|
|
29
|
+
compress: false,
|
|
30
|
+
compressionQuality: 0.5,
|
|
31
|
+
compressionFunction: undefined
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Write the soundfont as an .sf2 file. This method is DESTRUCTIVE
|
|
36
|
+
* @this {BasicSoundBank}
|
|
37
|
+
* @param {SoundFont2WriteOptions} options
|
|
38
|
+
* @returns {Uint8Array}
|
|
39
|
+
*/
|
|
40
|
+
export function write(options = DEFAULT_WRITE_OPTIONS)
|
|
41
|
+
{
|
|
42
|
+
if (options.compress)
|
|
43
|
+
{
|
|
44
|
+
if (typeof options.compressionFunction !== "function")
|
|
45
|
+
{
|
|
46
|
+
throw new TypeError("No compression function supplied but compression enabled.");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
SpessaSynthGroupCollapsed(
|
|
50
|
+
"%cSaving soundfont...",
|
|
51
|
+
consoleColors.info
|
|
52
|
+
);
|
|
53
|
+
SpessaSynthInfo(
|
|
54
|
+
`%cCompression: %c${options?.compress || "false"}%c quality: %c${options?.compressionQuality || "none"}`,
|
|
55
|
+
consoleColors.info,
|
|
56
|
+
consoleColors.recognized,
|
|
57
|
+
consoleColors.info,
|
|
58
|
+
consoleColors.recognized
|
|
59
|
+
);
|
|
60
|
+
SpessaSynthInfo(
|
|
61
|
+
"%cWriting INFO...",
|
|
62
|
+
consoleColors.info
|
|
63
|
+
);
|
|
64
|
+
/**
|
|
65
|
+
* Write INFO
|
|
66
|
+
* @type {IndexedByteArray[]}
|
|
67
|
+
*/
|
|
68
|
+
const infoArrays = [];
|
|
69
|
+
this.soundFontInfo["ISFT"] = "SpessaSynth"; // ( ͡° ͜ʖ ͡°)
|
|
70
|
+
if (options?.compress)
|
|
71
|
+
{
|
|
72
|
+
this.soundFontInfo["ifil"] = "3.0"; // set version to 3
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (const [type, data] of Object.entries(this.soundFontInfo))
|
|
76
|
+
{
|
|
77
|
+
if (type === "ifil" || type === "iver")
|
|
78
|
+
{
|
|
79
|
+
const major = parseInt(data.split(".")[0]);
|
|
80
|
+
const minor = parseInt(data.split(".")[1]);
|
|
81
|
+
const ckdata = new IndexedByteArray(4);
|
|
82
|
+
writeWord(ckdata, major);
|
|
83
|
+
writeWord(ckdata, minor);
|
|
84
|
+
infoArrays.push(writeRIFFChunk(new RiffChunk(
|
|
85
|
+
type,
|
|
86
|
+
4,
|
|
87
|
+
ckdata
|
|
88
|
+
)));
|
|
89
|
+
}
|
|
90
|
+
else if (type === "DMOD")
|
|
91
|
+
{
|
|
92
|
+
infoArrays.push(writeRIFFChunk(new RiffChunk(
|
|
93
|
+
type,
|
|
94
|
+
data.length,
|
|
95
|
+
data
|
|
96
|
+
)));
|
|
97
|
+
}
|
|
98
|
+
else
|
|
99
|
+
{
|
|
100
|
+
const arr = new IndexedByteArray(data.length);
|
|
101
|
+
writeStringAsBytes(arr, data);
|
|
102
|
+
infoArrays.push(writeRIFFChunk(new RiffChunk(
|
|
103
|
+
type,
|
|
104
|
+
data.length,
|
|
105
|
+
arr
|
|
106
|
+
)));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const combined = combineArrays([
|
|
110
|
+
new IndexedByteArray([73, 78, 70, 79]), // INFO
|
|
111
|
+
...infoArrays
|
|
112
|
+
]);
|
|
113
|
+
const infoChunk = writeRIFFChunk(new RiffChunk("LIST", combined.length, combined));
|
|
114
|
+
|
|
115
|
+
SpessaSynthInfo(
|
|
116
|
+
"%cWriting SDTA...",
|
|
117
|
+
consoleColors.info
|
|
118
|
+
);
|
|
119
|
+
// write sdta
|
|
120
|
+
const smplStartOffsets = [];
|
|
121
|
+
const smplEndOffsets = [];
|
|
122
|
+
const sdtaChunk = getSDTA.call(
|
|
123
|
+
this,
|
|
124
|
+
smplStartOffsets,
|
|
125
|
+
smplEndOffsets,
|
|
126
|
+
options?.compress,
|
|
127
|
+
options?.compressionQuality ?? 0.5,
|
|
128
|
+
options.compressionFunction
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
SpessaSynthInfo(
|
|
132
|
+
"%cWriting PDTA...",
|
|
133
|
+
consoleColors.info
|
|
134
|
+
);
|
|
135
|
+
// write pdta
|
|
136
|
+
// go in reverse so the indexes are correct
|
|
137
|
+
// instruments
|
|
138
|
+
SpessaSynthInfo(
|
|
139
|
+
"%cWriting SHDR...",
|
|
140
|
+
consoleColors.info
|
|
141
|
+
);
|
|
142
|
+
const shdrChunk = getSHDR.call(this, smplStartOffsets, smplEndOffsets);
|
|
143
|
+
SpessaSynthInfo(
|
|
144
|
+
"%cWriting IGEN...",
|
|
145
|
+
consoleColors.info
|
|
146
|
+
);
|
|
147
|
+
const igenChunk = getIGEN.call(this);
|
|
148
|
+
SpessaSynthInfo(
|
|
149
|
+
"%cWriting IMOD...",
|
|
150
|
+
consoleColors.info
|
|
151
|
+
);
|
|
152
|
+
const imodChunk = getIMOD.call(this);
|
|
153
|
+
SpessaSynthInfo(
|
|
154
|
+
"%cWriting IBAG...",
|
|
155
|
+
consoleColors.info
|
|
156
|
+
);
|
|
157
|
+
const ibagChunk = getIBAG.call(this);
|
|
158
|
+
SpessaSynthInfo(
|
|
159
|
+
"%cWriting INST...",
|
|
160
|
+
consoleColors.info
|
|
161
|
+
);
|
|
162
|
+
const instChunk = getINST.call(this);
|
|
163
|
+
// presets
|
|
164
|
+
const pgenChunk = getPGEN.call(this);
|
|
165
|
+
SpessaSynthInfo(
|
|
166
|
+
"%cWriting PMOD...",
|
|
167
|
+
consoleColors.info
|
|
168
|
+
);
|
|
169
|
+
const pmodChunk = getPMOD.call(this);
|
|
170
|
+
SpessaSynthInfo(
|
|
171
|
+
"%cWriting PBAG...",
|
|
172
|
+
consoleColors.info
|
|
173
|
+
);
|
|
174
|
+
const pbagChunk = getPBAG.call(this);
|
|
175
|
+
SpessaSynthInfo(
|
|
176
|
+
"%cWriting PHDR...",
|
|
177
|
+
consoleColors.info
|
|
178
|
+
);
|
|
179
|
+
const phdrChunk = getPHDR.call(this);
|
|
180
|
+
// combine in the sfspec order
|
|
181
|
+
const pdtadata = combineArrays([
|
|
182
|
+
new IndexedByteArray([112, 100, 116, 97]), // "pdta"
|
|
183
|
+
phdrChunk,
|
|
184
|
+
pbagChunk,
|
|
185
|
+
pmodChunk,
|
|
186
|
+
pgenChunk,
|
|
187
|
+
instChunk,
|
|
188
|
+
ibagChunk,
|
|
189
|
+
imodChunk,
|
|
190
|
+
igenChunk,
|
|
191
|
+
shdrChunk
|
|
192
|
+
]);
|
|
193
|
+
const pdtaChunk = writeRIFFChunk(new RiffChunk(
|
|
194
|
+
"LIST",
|
|
195
|
+
pdtadata.length,
|
|
196
|
+
pdtadata
|
|
197
|
+
));
|
|
198
|
+
SpessaSynthInfo(
|
|
199
|
+
"%cWriting the output file...",
|
|
200
|
+
consoleColors.info
|
|
201
|
+
);
|
|
202
|
+
// finally, combine everything
|
|
203
|
+
const riffdata = combineArrays([
|
|
204
|
+
new IndexedByteArray([115, 102, 98, 107]), // "sfbk"
|
|
205
|
+
infoChunk,
|
|
206
|
+
sdtaChunk,
|
|
207
|
+
pdtaChunk
|
|
208
|
+
]);
|
|
209
|
+
|
|
210
|
+
const main = writeRIFFChunk(new RiffChunk(
|
|
211
|
+
"RIFF",
|
|
212
|
+
riffdata.length,
|
|
213
|
+
riffdata
|
|
214
|
+
));
|
|
215
|
+
SpessaSynthInfo(
|
|
216
|
+
`%cSaved succesfully! Final file size: %c${main.length}`,
|
|
217
|
+
consoleColors.info,
|
|
218
|
+
consoleColors.recognized
|
|
219
|
+
);
|
|
220
|
+
SpessaSynthGroupEnd();
|
|
221
|
+
return main;
|
|
222
|
+
}
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import { DLSSources } from "./dls_sources.js";
|
|
2
|
+
import { getModSourceEnum, Modulator, modulatorCurveTypes, modulatorSources } from "../basic_soundfont/modulator.js";
|
|
3
|
+
import { midiControllers } from "../../midi/midi_message.js";
|
|
4
|
+
import { DLSDestinations } from "./dls_destinations.js";
|
|
5
|
+
|
|
6
|
+
import { generatorTypes } from "../basic_soundfont/generator.js";
|
|
7
|
+
import { consoleColors } from "../../utils/other.js";
|
|
8
|
+
import { SpessaSynthWarn } from "../../utils/loggin.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param source {number}
|
|
12
|
+
* @returns {{enum: number, isCC: boolean}|undefined}
|
|
13
|
+
*/
|
|
14
|
+
function getSF2SourceFromDLS(source)
|
|
15
|
+
{
|
|
16
|
+
let sourceEnum = undefined;
|
|
17
|
+
let isCC = false;
|
|
18
|
+
switch (source)
|
|
19
|
+
{
|
|
20
|
+
default:
|
|
21
|
+
case DLSSources.modLfo:
|
|
22
|
+
case DLSSources.vibratoLfo:
|
|
23
|
+
case DLSSources.coarseTune:
|
|
24
|
+
case DLSSources.fineTune:
|
|
25
|
+
case DLSSources.modEnv:
|
|
26
|
+
return undefined; // cannot be this in sf2
|
|
27
|
+
|
|
28
|
+
case DLSSources.keyNum:
|
|
29
|
+
sourceEnum = modulatorSources.noteOnKeyNum;
|
|
30
|
+
break;
|
|
31
|
+
case DLSSources.none:
|
|
32
|
+
sourceEnum = modulatorSources.noController;
|
|
33
|
+
break;
|
|
34
|
+
case DLSSources.modulationWheel:
|
|
35
|
+
sourceEnum = midiControllers.modulationWheel;
|
|
36
|
+
isCC = true;
|
|
37
|
+
break;
|
|
38
|
+
case DLSSources.pan:
|
|
39
|
+
sourceEnum = midiControllers.pan;
|
|
40
|
+
isCC = true;
|
|
41
|
+
break;
|
|
42
|
+
case DLSSources.reverb:
|
|
43
|
+
sourceEnum = midiControllers.reverbDepth;
|
|
44
|
+
isCC = true;
|
|
45
|
+
break;
|
|
46
|
+
case DLSSources.chorus:
|
|
47
|
+
sourceEnum = midiControllers.chorusDepth;
|
|
48
|
+
isCC = true;
|
|
49
|
+
break;
|
|
50
|
+
case DLSSources.expression:
|
|
51
|
+
sourceEnum = midiControllers.expressionController;
|
|
52
|
+
isCC = true;
|
|
53
|
+
break;
|
|
54
|
+
case DLSSources.volume:
|
|
55
|
+
sourceEnum = midiControllers.mainVolume;
|
|
56
|
+
isCC = true;
|
|
57
|
+
break;
|
|
58
|
+
case DLSSources.velocity:
|
|
59
|
+
sourceEnum = modulatorSources.noteOnVelocity;
|
|
60
|
+
break;
|
|
61
|
+
case DLSSources.polyPressure:
|
|
62
|
+
sourceEnum = modulatorSources.polyPressure;
|
|
63
|
+
break;
|
|
64
|
+
case DLSSources.channelPressure:
|
|
65
|
+
sourceEnum = modulatorSources.channelPressure;
|
|
66
|
+
break;
|
|
67
|
+
case DLSSources.pitchWheel:
|
|
68
|
+
sourceEnum = modulatorSources.pitchWheel;
|
|
69
|
+
break;
|
|
70
|
+
case DLSSources.pitchWheelRange:
|
|
71
|
+
sourceEnum = modulatorSources.pitchWheelRange;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
if (sourceEnum === undefined)
|
|
75
|
+
{
|
|
76
|
+
throw new Error(`Unknown DLS Source: ${source}`);
|
|
77
|
+
}
|
|
78
|
+
return { enum: sourceEnum, isCC: isCC };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @param destination {number}
|
|
83
|
+
* @param amount {number}
|
|
84
|
+
* @returns {generatorTypes|{gen: generatorTypes, newAmount: number}} // transform amount to sf2 units
|
|
85
|
+
*/
|
|
86
|
+
function getSF2GeneratorFromDLS(destination, amount)
|
|
87
|
+
{
|
|
88
|
+
switch (destination)
|
|
89
|
+
{
|
|
90
|
+
default:
|
|
91
|
+
case DLSDestinations.none:
|
|
92
|
+
return undefined;
|
|
93
|
+
case DLSDestinations.pan:
|
|
94
|
+
return generatorTypes.pan;
|
|
95
|
+
case DLSDestinations.gain:
|
|
96
|
+
return { gen: generatorTypes.initialAttenuation, newAmount: amount * -1 };
|
|
97
|
+
case DLSDestinations.pitch:
|
|
98
|
+
return generatorTypes.fineTune;
|
|
99
|
+
case DLSDestinations.keyNum:
|
|
100
|
+
return generatorTypes.overridingRootKey;
|
|
101
|
+
|
|
102
|
+
// vol env
|
|
103
|
+
case DLSDestinations.volEnvDelay:
|
|
104
|
+
return generatorTypes.delayVolEnv;
|
|
105
|
+
case DLSDestinations.volEnvAttack:
|
|
106
|
+
return generatorTypes.attackVolEnv;
|
|
107
|
+
case DLSDestinations.volEnvHold:
|
|
108
|
+
return generatorTypes.holdVolEnv;
|
|
109
|
+
case DLSDestinations.volEnvDecay:
|
|
110
|
+
return generatorTypes.decayVolEnv;
|
|
111
|
+
case DLSDestinations.volEnvSustain:
|
|
112
|
+
return { gen: generatorTypes.sustainVolEnv, newAmount: 1000 - amount };
|
|
113
|
+
case DLSDestinations.volEnvRelease:
|
|
114
|
+
return generatorTypes.releaseVolEnv;
|
|
115
|
+
|
|
116
|
+
// mod env
|
|
117
|
+
case DLSDestinations.modEnvDelay:
|
|
118
|
+
return generatorTypes.delayModEnv;
|
|
119
|
+
case DLSDestinations.modEnvAttack:
|
|
120
|
+
return generatorTypes.attackModEnv;
|
|
121
|
+
case DLSDestinations.modEnvHold:
|
|
122
|
+
return generatorTypes.holdModEnv;
|
|
123
|
+
case DLSDestinations.modEnvDecay:
|
|
124
|
+
return generatorTypes.decayModEnv;
|
|
125
|
+
case DLSDestinations.modEnvSustain:
|
|
126
|
+
return { gen: generatorTypes.sustainModEnv, newAmount: (1000 - amount) / 10 };
|
|
127
|
+
case DLSDestinations.modEnvRelease:
|
|
128
|
+
return generatorTypes.releaseModEnv;
|
|
129
|
+
|
|
130
|
+
case DLSDestinations.filterCutoff:
|
|
131
|
+
return generatorTypes.initialFilterFc;
|
|
132
|
+
case DLSDestinations.filterQ:
|
|
133
|
+
return generatorTypes.initialFilterQ;
|
|
134
|
+
case DLSDestinations.chorusSend:
|
|
135
|
+
return generatorTypes.chorusEffectsSend;
|
|
136
|
+
case DLSDestinations.reverbSend:
|
|
137
|
+
return generatorTypes.reverbEffectsSend;
|
|
138
|
+
|
|
139
|
+
// lfo
|
|
140
|
+
case DLSDestinations.modLfoFreq:
|
|
141
|
+
return generatorTypes.freqModLFO;
|
|
142
|
+
case DLSDestinations.modLfoDelay:
|
|
143
|
+
return generatorTypes.delayModLFO;
|
|
144
|
+
case DLSDestinations.vibLfoFreq:
|
|
145
|
+
return generatorTypes.freqVibLFO;
|
|
146
|
+
case DLSDestinations.vibLfoDelay:
|
|
147
|
+
return generatorTypes.delayVibLFO;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* checks for combos such as mod lfo as source and pitch as destination which results in modLfoToPitch
|
|
153
|
+
* @param source {number}
|
|
154
|
+
* @param destination {number}
|
|
155
|
+
* @returns {generatorTypes} real destination
|
|
156
|
+
*/
|
|
157
|
+
function checkForSpecialDLSCombo(source, destination)
|
|
158
|
+
{
|
|
159
|
+
if (source === DLSSources.vibratoLfo && destination === DLSDestinations.pitch)
|
|
160
|
+
{
|
|
161
|
+
// vibrato lfo to pitch
|
|
162
|
+
return generatorTypes.vibLfoToPitch;
|
|
163
|
+
}
|
|
164
|
+
else if (source === DLSSources.modLfo && destination === DLSDestinations.pitch)
|
|
165
|
+
{
|
|
166
|
+
// mod lfo to pitch
|
|
167
|
+
return generatorTypes.modLfoToPitch;
|
|
168
|
+
}
|
|
169
|
+
else if (source === DLSSources.modLfo && destination === DLSDestinations.filterCutoff)
|
|
170
|
+
{
|
|
171
|
+
// mod lfo to filter
|
|
172
|
+
return generatorTypes.modLfoToFilterFc;
|
|
173
|
+
}
|
|
174
|
+
else if (source === DLSSources.modLfo && destination === DLSDestinations.gain)
|
|
175
|
+
{
|
|
176
|
+
// mod lfo to volume
|
|
177
|
+
return generatorTypes.modLfoToVolume;
|
|
178
|
+
}
|
|
179
|
+
else if (source === DLSSources.modEnv && destination === DLSDestinations.filterCutoff)
|
|
180
|
+
{
|
|
181
|
+
// mod envelope to filter
|
|
182
|
+
return generatorTypes.modEnvToFilterFc;
|
|
183
|
+
}
|
|
184
|
+
else if (source === DLSSources.modEnv && destination === DLSDestinations.pitch)
|
|
185
|
+
{
|
|
186
|
+
// mod envelope to pitch
|
|
187
|
+
return generatorTypes.modEnvToPitch;
|
|
188
|
+
}
|
|
189
|
+
else
|
|
190
|
+
{
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// noinspection JSUnusedGlobalSymbols
|
|
196
|
+
/**
|
|
197
|
+
* @param source {number}
|
|
198
|
+
* @param control {number}
|
|
199
|
+
* @param destination {number}
|
|
200
|
+
* @param value {number}
|
|
201
|
+
* @param transform {number}
|
|
202
|
+
* @param msg {string}
|
|
203
|
+
*/
|
|
204
|
+
export function modulatorConverterDebug(
|
|
205
|
+
source,
|
|
206
|
+
control,
|
|
207
|
+
destination,
|
|
208
|
+
value,
|
|
209
|
+
transform,
|
|
210
|
+
msg = "Attempting to convert the following DLS Articulator to SF2 Modulator:"
|
|
211
|
+
)
|
|
212
|
+
{
|
|
213
|
+
const type = Object.keys(DLSDestinations).find(k => DLSDestinations[k] === destination);
|
|
214
|
+
const srcType = Object.keys(DLSSources).find(k => DLSSources[k] === source);
|
|
215
|
+
const ctrlType = Object.keys(DLSSources).find(k => DLSSources[k] === control);
|
|
216
|
+
const typeString = type ? type : destination.toString(16);
|
|
217
|
+
const srcString = srcType ? srcType : source.toString(16);
|
|
218
|
+
const ctrlString = ctrlType ? ctrlType : control.toString(16);
|
|
219
|
+
console.debug(
|
|
220
|
+
`%c${msg}
|
|
221
|
+
Source: %c${srcString}%c
|
|
222
|
+
Control: %c${ctrlString}%c
|
|
223
|
+
Destination: %c${typeString}%c
|
|
224
|
+
Amount: %c${value}%c
|
|
225
|
+
Transform: %c${transform}%c...`,
|
|
226
|
+
consoleColors.info,
|
|
227
|
+
consoleColors.recognized,
|
|
228
|
+
consoleColors.info,
|
|
229
|
+
consoleColors.recognized,
|
|
230
|
+
consoleColors.info,
|
|
231
|
+
consoleColors.recognized,
|
|
232
|
+
consoleColors.info,
|
|
233
|
+
consoleColors.recognized,
|
|
234
|
+
consoleColors.info,
|
|
235
|
+
consoleColors.recognized,
|
|
236
|
+
consoleColors.info
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* @param source {number}
|
|
242
|
+
* @param control {number}
|
|
243
|
+
* @param destination {number}
|
|
244
|
+
* @param transform {number}
|
|
245
|
+
* @param value {number}
|
|
246
|
+
* @returns {Modulator|undefined}
|
|
247
|
+
*/
|
|
248
|
+
export function getSF2ModulatorFromArticulator(
|
|
249
|
+
source,
|
|
250
|
+
control,
|
|
251
|
+
destination,
|
|
252
|
+
transform,
|
|
253
|
+
value
|
|
254
|
+
)
|
|
255
|
+
{
|
|
256
|
+
// modulatorConverterDebug(
|
|
257
|
+
// source,
|
|
258
|
+
// control,
|
|
259
|
+
// destination,
|
|
260
|
+
// value,
|
|
261
|
+
// transform
|
|
262
|
+
// );
|
|
263
|
+
// check for special combinations
|
|
264
|
+
const specialDestination = checkForSpecialDLSCombo(source, destination);
|
|
265
|
+
/**
|
|
266
|
+
* @type {generatorTypes}
|
|
267
|
+
*/
|
|
268
|
+
let destinationGenerator;
|
|
269
|
+
/**
|
|
270
|
+
* @type {{enum: number, isCC: boolean}}
|
|
271
|
+
*/
|
|
272
|
+
let sf2Source;
|
|
273
|
+
let swapSources = false;
|
|
274
|
+
let isSourceNoController = false;
|
|
275
|
+
let newValue = value;
|
|
276
|
+
if (specialDestination === undefined)
|
|
277
|
+
{
|
|
278
|
+
// determine destination
|
|
279
|
+
const sf2GenDestination = getSF2GeneratorFromDLS(destination, value);
|
|
280
|
+
if (sf2GenDestination === undefined)
|
|
281
|
+
{
|
|
282
|
+
// cannot be a valid modulator
|
|
283
|
+
SpessaSynthWarn(`Invalid destination: ${destination}`);
|
|
284
|
+
return undefined;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* @type {generatorTypes}
|
|
288
|
+
*/
|
|
289
|
+
destinationGenerator = sf2GenDestination;
|
|
290
|
+
if (sf2GenDestination.newAmount !== undefined)
|
|
291
|
+
{
|
|
292
|
+
newValue = sf2GenDestination.newAmount;
|
|
293
|
+
destinationGenerator = sf2GenDestination.gen;
|
|
294
|
+
}
|
|
295
|
+
sf2Source = getSF2SourceFromDLS(source);
|
|
296
|
+
if (sf2Source === undefined)
|
|
297
|
+
{
|
|
298
|
+
// cannot be a valid modulator
|
|
299
|
+
SpessaSynthWarn(`Invalid source: ${source}`);
|
|
300
|
+
return undefined;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else
|
|
304
|
+
{
|
|
305
|
+
destinationGenerator = specialDestination;
|
|
306
|
+
swapSources = true;
|
|
307
|
+
sf2Source = { enum: modulatorSources.noController, isCC: false };
|
|
308
|
+
isSourceNoController = true;
|
|
309
|
+
}
|
|
310
|
+
let sf2SecondSource = getSF2SourceFromDLS(control);
|
|
311
|
+
if (sf2SecondSource === undefined)
|
|
312
|
+
{
|
|
313
|
+
// cannot be a valid modulator
|
|
314
|
+
SpessaSynthWarn(`Invalid control: ${control}`);
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// get transforms and final enums
|
|
319
|
+
let sourceEnumFinal;
|
|
320
|
+
if (isSourceNoController)
|
|
321
|
+
{
|
|
322
|
+
// we force it into this state because before it was some strange value,
|
|
323
|
+
// like vibrato lfo bipolar, for example,
|
|
324
|
+
// since we turn it into NoController -> vibLfoToPitch,
|
|
325
|
+
// the result is the same and bipolar controller is technically 0
|
|
326
|
+
sourceEnumFinal = 0x0;
|
|
327
|
+
}
|
|
328
|
+
else
|
|
329
|
+
{
|
|
330
|
+
// output transform is ignored as it's not a thing in sfont format
|
|
331
|
+
// unless the curve type of source is linear, then output is copied
|
|
332
|
+
const outputTransform = transform & 0b1111;
|
|
333
|
+
// source curve type maps to a desfont curve type in section 2.10, table 9
|
|
334
|
+
let sourceTransform = (transform >> 10) & 0b1111;
|
|
335
|
+
if (sourceTransform === modulatorCurveTypes.linear && outputTransform !== modulatorCurveTypes.linear)
|
|
336
|
+
{
|
|
337
|
+
sourceTransform = outputTransform;
|
|
338
|
+
}
|
|
339
|
+
const sourceIsBipolar = (transform >> 14) & 1;
|
|
340
|
+
let sourceIsNegative = (transform >> 15) & 1;
|
|
341
|
+
// special case: for attenuation, invert source (dls gain is the opposite of sf2 attenuation)
|
|
342
|
+
if (destinationGenerator === generatorTypes.initialAttenuation)
|
|
343
|
+
{
|
|
344
|
+
// if the value is negative, the source shall be negative!
|
|
345
|
+
// why?
|
|
346
|
+
// IDK, it makes it work with ROCK.RMI and NOKIA_S30.dls
|
|
347
|
+
if (value < 0)
|
|
348
|
+
{
|
|
349
|
+
sourceIsNegative = 1;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
sourceEnumFinal = getModSourceEnum(
|
|
353
|
+
sourceTransform,
|
|
354
|
+
sourceIsBipolar,
|
|
355
|
+
sourceIsNegative,
|
|
356
|
+
sf2Source.isCC,
|
|
357
|
+
sf2Source.enum
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// a corrupted rendition of gm.dls was found under
|
|
362
|
+
// https://sembiance.com/fileFormatSamples/audio/downloadableSoundBank/
|
|
363
|
+
// which specifies a whopping -32,768 decibels of attenuation
|
|
364
|
+
if (destinationGenerator === generatorTypes.initialAttenuation)
|
|
365
|
+
{
|
|
366
|
+
newValue = Math.max(960, Math.min(0, newValue));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const secSourceTransform = (transform >> 4) & 0b1111;
|
|
370
|
+
const secSourceIsBipolar = (transform >> 8) & 1;
|
|
371
|
+
const secSourceIsNegative = transform >> 9 & 1;
|
|
372
|
+
let secSourceEnumFinal = getModSourceEnum(
|
|
373
|
+
secSourceTransform,
|
|
374
|
+
secSourceIsBipolar,
|
|
375
|
+
secSourceIsNegative,
|
|
376
|
+
sf2SecondSource.isCC,
|
|
377
|
+
sf2SecondSource.enum
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
if (swapSources)
|
|
381
|
+
{
|
|
382
|
+
const temp = secSourceEnumFinal;
|
|
383
|
+
secSourceEnumFinal = sourceEnumFinal;
|
|
384
|
+
sourceEnumFinal = temp;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// return the modulator!
|
|
388
|
+
return new Modulator(
|
|
389
|
+
sourceEnumFinal,
|
|
390
|
+
secSourceEnumFinal,
|
|
391
|
+
destinationGenerator,
|
|
392
|
+
newValue,
|
|
393
|
+
0x0
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @enum {number}
|
|
4
|
+
*/
|
|
5
|
+
export const DLSDestinations = {
|
|
6
|
+
none: 0x0, // no destination
|
|
7
|
+
gain: 0x1, // linear gain
|
|
8
|
+
reserved: 0x2, // reserved
|
|
9
|
+
pitch: 0x3, // pitch in cents
|
|
10
|
+
pan: 0x4, // pan 10ths of a percent
|
|
11
|
+
keyNum: 0x5, // MIDI key number
|
|
12
|
+
// nuh uh, the channel controllers are not supported!
|
|
13
|
+
chorusSend: 0x80, // chorus send level 10ths of a percent
|
|
14
|
+
reverbSend: 0x81, // reverb send level 10ths of a percent
|
|
15
|
+
|
|
16
|
+
modLfoFreq: 0x104, // modulation LFO frequency
|
|
17
|
+
modLfoDelay: 0x105, // modulation LFO delay
|
|
18
|
+
|
|
19
|
+
vibLfoFreq: 0x114, // vibrato LFO frequency
|
|
20
|
+
vibLfoDelay: 0x115, // vibrato LFO delay
|
|
21
|
+
|
|
22
|
+
volEnvAttack: 0x206, // volume envelope attack
|
|
23
|
+
volEnvDecay: 0x207, // volume envelope decay
|
|
24
|
+
volEnvRelease: 0x209, // volume envelope release
|
|
25
|
+
volEnvSustain: 0x20a, // volume envelope sustain
|
|
26
|
+
volEnvDelay: 0x20b, // volume envelope delay
|
|
27
|
+
volEnvHold: 0x20c, // volume envelope hold
|
|
28
|
+
|
|
29
|
+
modEnvAttack: 0x30a, // modulation envelope attack
|
|
30
|
+
modEnvDecay: 0x30b, // modulation envelope decay
|
|
31
|
+
modEnvRelease: 0x30d, // modulation envelope release
|
|
32
|
+
modEnvSustain: 0x30e, // modulation envelope sustain
|
|
33
|
+
modEnvDelay: 0x30f, // modulation envelope delay
|
|
34
|
+
modEnvHold: 0x310, // modulation envelope hold
|
|
35
|
+
|
|
36
|
+
filterCutoff: 0x500, // low pass filter cutoff frequency
|
|
37
|
+
filterQ: 0x501 // low pass filter resonance
|
|
38
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BasicPreset } from "../basic_soundfont/basic_preset.js";
|
|
2
|
+
import { BasicPresetZone } from "../basic_soundfont/basic_zones.js";
|
|
3
|
+
import { BasicInstrument } from "../basic_soundfont/basic_instrument.js";
|
|
4
|
+
|
|
5
|
+
export class DLSPreset extends BasicPreset
|
|
6
|
+
{
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new DLS preset
|
|
9
|
+
* @param dls {BasicSoundBank}
|
|
10
|
+
* @param ulBank {number}
|
|
11
|
+
* @param ulInstrument {number}
|
|
12
|
+
*/
|
|
13
|
+
constructor(dls, ulBank, ulInstrument)
|
|
14
|
+
{
|
|
15
|
+
// use stock default modulators, dls won't ever have DMOD chunk
|
|
16
|
+
super(dls);
|
|
17
|
+
this.program = ulInstrument & 127;
|
|
18
|
+
const bankMSB = (ulBank >> 8) & 127;
|
|
19
|
+
const bankLSB = ulBank & 127;
|
|
20
|
+
// switch accordingly
|
|
21
|
+
if (bankMSB > 0)
|
|
22
|
+
{
|
|
23
|
+
this.bank = bankMSB;
|
|
24
|
+
}
|
|
25
|
+
else
|
|
26
|
+
{
|
|
27
|
+
this.bank = bankLSB;
|
|
28
|
+
}
|
|
29
|
+
const isDrums = ulBank >> 31;
|
|
30
|
+
if (isDrums)
|
|
31
|
+
{
|
|
32
|
+
// soundfont bank is 128, so we change it here
|
|
33
|
+
this.bank = 128;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.DLSInstrument = new BasicInstrument();
|
|
37
|
+
this.DLSInstrument.addUseCount();
|
|
38
|
+
|
|
39
|
+
const zone = new BasicPresetZone();
|
|
40
|
+
zone.instrument = this.DLSInstrument;
|
|
41
|
+
|
|
42
|
+
this.presetZones = [zone];
|
|
43
|
+
}
|
|
44
|
+
}
|