spessasynth_lib 3.25.23 → 3.26.1

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.
Files changed (162) hide show
  1. package/README.md +29 -114
  2. package/external_midi/midi_handler.js +14 -14
  3. package/external_midi/web_midi_link.js +3 -3
  4. package/index.js +33 -33
  5. package/package.json +19 -6
  6. package/{midi → sequencer}/midi_data.js +1 -1
  7. package/sequencer/{worklet_wrapper/sequencer.js → sequencer.js} +13 -12
  8. package/sequencer/{worklet_wrapper/sequencer_message.js → sequencer_message.js} +1 -1
  9. package/synthetizer/README.md +29 -1
  10. package/synthetizer/audio_effects/reverb_as_binary.js +2 -2
  11. package/synthetizer/{worklet_wrapper/key_modifier_manager.js → key_modifier_manager.js} +11 -2
  12. package/synthetizer/{worklet_wrapper/synth_event_handler.js → synth_event_handler.js} +16 -13
  13. package/synthetizer/{worklet_wrapper/synth_soundfont_manager.js → synth_soundfont_manager.js} +8 -5
  14. package/synthetizer/{worklet_wrapper/synthetizer.js → synthetizer.js} +29 -23
  15. package/synthetizer/{audio_engine/message_protocol/worklet_message.js → worklet_message.js} +15 -2
  16. package/synthetizer/{worklet_wrapper/worklet_processor.js → worklet_processor.js} +214 -31
  17. package/synthetizer/worklet_processor.min.js +13 -12
  18. package/synthetizer/worklet_processor.min.js.map +7 -0
  19. package/synthetizer/{worklet_wrapper/worklet_url.js → worklet_url.js} +2 -0
  20. package/utils/buffer_to_wav.js +7 -165
  21. package/utils/other.js +3 -84
  22. package/externals/fflate/LICENSE +0 -21
  23. package/externals/fflate/fflate.min.js +0 -1
  24. package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  25. package/externals/stbvorbis_sync/LICENSE +0 -202
  26. package/externals/stbvorbis_sync/NOTICE +0 -6
  27. package/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  28. package/midi/README.md +0 -32
  29. package/midi/basic_midi.js +0 -565
  30. package/midi/midi_builder.js +0 -202
  31. package/midi/midi_loader.js +0 -324
  32. package/midi/midi_message.js +0 -254
  33. package/midi/midi_sequence.js +0 -225
  34. package/midi/midi_tools/get_note_times.js +0 -154
  35. package/midi/midi_tools/midi_editor.js +0 -611
  36. package/midi/midi_tools/midi_writer.js +0 -99
  37. package/midi/midi_tools/rmidi_writer.js +0 -567
  38. package/midi/midi_tools/used_keys_loaded.js +0 -238
  39. package/midi/xmf_loader.js +0 -454
  40. package/sequencer/sequencer_engine/events.js +0 -104
  41. package/sequencer/sequencer_engine/play.js +0 -353
  42. package/sequencer/sequencer_engine/process_event.js +0 -169
  43. package/sequencer/sequencer_engine/process_tick.js +0 -106
  44. package/sequencer/sequencer_engine/sequencer_engine.js +0 -335
  45. package/sequencer/sequencer_engine/song_control.js +0 -229
  46. package/soundfont/README.md +0 -13
  47. package/soundfont/basic_soundfont/basic_instrument.js +0 -77
  48. package/soundfont/basic_soundfont/basic_preset.js +0 -336
  49. package/soundfont/basic_soundfont/basic_sample.js +0 -197
  50. package/soundfont/basic_soundfont/basic_soundfont.js +0 -565
  51. package/soundfont/basic_soundfont/basic_zone.js +0 -64
  52. package/soundfont/basic_soundfont/basic_zones.js +0 -43
  53. package/soundfont/basic_soundfont/generator.js +0 -220
  54. package/soundfont/basic_soundfont/modulator.js +0 -378
  55. package/soundfont/basic_soundfont/riff_chunk.js +0 -149
  56. package/soundfont/basic_soundfont/write_dls/art2.js +0 -173
  57. package/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  58. package/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -400
  59. package/soundfont/basic_soundfont/write_dls/ins.js +0 -103
  60. package/soundfont/basic_soundfont/write_dls/lins.js +0 -18
  61. package/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  62. package/soundfont/basic_soundfont/write_dls/rgn2.js +0 -121
  63. package/soundfont/basic_soundfont/write_dls/wave.js +0 -94
  64. package/soundfont/basic_soundfont/write_dls/write_dls.js +0 -119
  65. package/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  66. package/soundfont/basic_soundfont/write_dls/wvpl.js +0 -32
  67. package/soundfont/basic_soundfont/write_sf2/ibag.js +0 -39
  68. package/soundfont/basic_soundfont/write_sf2/igen.js +0 -80
  69. package/soundfont/basic_soundfont/write_sf2/imod.js +0 -46
  70. package/soundfont/basic_soundfont/write_sf2/inst.js +0 -34
  71. package/soundfont/basic_soundfont/write_sf2/pbag.js +0 -39
  72. package/soundfont/basic_soundfont/write_sf2/pgen.js +0 -82
  73. package/soundfont/basic_soundfont/write_sf2/phdr.js +0 -42
  74. package/soundfont/basic_soundfont/write_sf2/pmod.js +0 -46
  75. package/soundfont/basic_soundfont/write_sf2/sdta.js +0 -80
  76. package/soundfont/basic_soundfont/write_sf2/shdr.js +0 -55
  77. package/soundfont/basic_soundfont/write_sf2/write.js +0 -222
  78. package/soundfont/dls/articulator_converter.js +0 -396
  79. package/soundfont/dls/dls_destinations.js +0 -38
  80. package/soundfont/dls/dls_preset.js +0 -44
  81. package/soundfont/dls/dls_sample.js +0 -75
  82. package/soundfont/dls/dls_soundfont.js +0 -186
  83. package/soundfont/dls/dls_sources.js +0 -62
  84. package/soundfont/dls/dls_zone.js +0 -95
  85. package/soundfont/dls/read_articulation.js +0 -299
  86. package/soundfont/dls/read_instrument.js +0 -121
  87. package/soundfont/dls/read_instrument_list.js +0 -17
  88. package/soundfont/dls/read_lart.js +0 -35
  89. package/soundfont/dls/read_region.js +0 -152
  90. package/soundfont/dls/read_samples.js +0 -270
  91. package/soundfont/load_soundfont.js +0 -21
  92. package/soundfont/read_sf2/generators.js +0 -46
  93. package/soundfont/read_sf2/instruments.js +0 -66
  94. package/soundfont/read_sf2/modulators.js +0 -36
  95. package/soundfont/read_sf2/presets.js +0 -80
  96. package/soundfont/read_sf2/samples.js +0 -304
  97. package/soundfont/read_sf2/soundfont.js +0 -305
  98. package/soundfont/read_sf2/zones.js +0 -263
  99. package/synthetizer/audio_engine/README.md +0 -25
  100. package/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -266
  101. package/synthetizer/audio_engine/engine_components/controller_tables.js +0 -88
  102. package/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -149
  103. package/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  104. package/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  105. package/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -471
  106. package/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  107. package/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  108. package/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -228
  109. package/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -120
  110. package/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  111. package/synthetizer/audio_engine/engine_components/voice.js +0 -519
  112. package/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -401
  113. package/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -263
  114. package/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -132
  115. package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
  116. package/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -241
  117. package/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -27
  118. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -253
  119. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -66
  120. package/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  121. package/synthetizer/audio_engine/engine_methods/note_on.js +0 -175
  122. package/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  123. package/synthetizer/audio_engine/engine_methods/program_change.js +0 -61
  124. package/synthetizer/audio_engine/engine_methods/render_voice.js +0 -196
  125. package/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -30
  126. package/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
  127. package/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +0 -40
  128. package/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +0 -34
  129. package/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -21
  130. package/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -20
  131. package/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -55
  132. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  133. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  134. package/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  135. package/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -776
  136. package/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -24
  137. package/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -33
  138. package/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -31
  139. package/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  140. package/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -27
  141. package/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  142. package/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  143. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  144. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  145. package/synthetizer/audio_engine/main_processor.js +0 -765
  146. package/synthetizer/audio_engine/message_protocol/README.md +0 -13
  147. package/synthetizer/audio_engine/message_protocol/message_sending.js +0 -22
  148. package/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -14
  149. package/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  150. package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -122
  151. package/synthetizer/synth_constants.js +0 -20
  152. package/utils/README.md +0 -5
  153. package/utils/byte_functions/big_endian.js +0 -32
  154. package/utils/byte_functions/little_endian.js +0 -77
  155. package/utils/byte_functions/string.js +0 -107
  156. package/utils/byte_functions/variable_length_quantity.js +0 -42
  157. package/utils/indexed_array.js +0 -52
  158. package/utils/loggin.js +0 -79
  159. package/utils/sysex_detector.js +0 -58
  160. package/utils/xg_hacks.js +0 -193
  161. /package/sequencer/{worklet_wrapper/default_sequencer_options.js → default_sequencer_options.js} +0 -0
  162. /package/synthetizer/{worklet_wrapper/sfman_message.js → sfman_message.js} +0 -0
@@ -1,565 +0,0 @@
1
- import {
2
- SpessaSynthGroup,
3
- SpessaSynthGroupCollapsed,
4
- SpessaSynthGroupEnd,
5
- SpessaSynthInfo,
6
- SpessaSynthWarn
7
- } from "../../utils/loggin.js";
8
- import { consoleColors } from "../../utils/other.js";
9
- import { write } from "./write_sf2/write.js";
10
- import { defaultModulators, Modulator } from "./modulator.js";
11
- import { writeDLS } from "./write_dls/write_dls.js";
12
- import { BasicSample } from "./basic_sample.js";
13
- import { BasicInstrumentZone, BasicPresetZone } from "./basic_zones.js";
14
- import { Generator, generatorTypes } from "./generator.js";
15
- import { BasicInstrument } from "./basic_instrument.js";
16
- import { BasicPreset } from "./basic_preset.js";
17
- import { isXGDrums } from "../../utils/xg_hacks.js";
18
-
19
- class BasicSoundBank
20
- {
21
-
22
- /**
23
- * Soundfont's info stored as name: value. ifil and iver are stored as string representation of float (e.g., 2.1)
24
- * @type {Object<string, string|IndexedByteArray>}
25
- */
26
- soundFontInfo = {};
27
-
28
- /**
29
- * The soundfont's presets
30
- * @type {BasicPreset[]}
31
- */
32
- presets = [];
33
-
34
- /**
35
- * The soundfont's samples
36
- * @type {BasicSample[]}
37
- */
38
- samples = [];
39
-
40
- /**
41
- * The soundfont's instruments
42
- * @type {BasicInstrument[]}
43
- */
44
- instruments = [];
45
-
46
- /**
47
- * Soundfont's default modulatorss
48
- * @type {Modulator[]}
49
- */
50
- defaultModulators = defaultModulators.map(m => Modulator.copy(m));
51
-
52
- /**
53
- * Checks for XG drumsets and considers if this soundfont is XG.
54
- * @type {boolean}
55
- */
56
- isXGBank = false;
57
-
58
- /**
59
- * Creates a new basic soundfont template
60
- * @param data {undefined|{presets: BasicPreset[], info: Object<string, string>}}
61
- */
62
- constructor(data = undefined)
63
- {
64
- if (data?.presets)
65
- {
66
- this.presets.push(...data.presets);
67
- this.soundFontInfo = data.info;
68
- }
69
- }
70
-
71
- /**
72
- * Merges soundfonts with the given order. Keep in mind that the info read is copied from the first one
73
- * @param soundfonts {...BasicSoundBank} the soundfonts to merge, the first overwrites the last
74
- * @returns {BasicSoundBank}
75
- */
76
- static mergeSoundBanks(...soundfonts)
77
- {
78
- const mainSf = soundfonts.shift();
79
- const presets = mainSf.presets;
80
- while (soundfonts.length)
81
- {
82
- const newPresets = soundfonts.shift().presets;
83
- newPresets.forEach(newPreset =>
84
- {
85
- if (
86
- presets.find(existingPreset => existingPreset.bank === newPreset.bank && existingPreset.program === newPreset.program) === undefined
87
- )
88
- {
89
- presets.push(newPreset);
90
- }
91
- });
92
- }
93
-
94
- return new BasicSoundBank({ presets: presets, info: mainSf.soundFontInfo });
95
- }
96
-
97
- /**
98
- * Creates a simple soundfont with one saw wave preset.
99
- * @returns {ArrayBufferLike}
100
- */
101
- static getDummySoundfontFile()
102
- {
103
- const font = new BasicSoundBank();
104
- const sample = new BasicSample(
105
- "Saw",
106
- 44100,
107
- 65,
108
- 20,
109
- 0,
110
- 0,
111
- 0,
112
- 127
113
- );
114
- sample.sampleData = new Float32Array(128);
115
- for (let i = 0; i < 128; i++)
116
- {
117
- sample.sampleData[i] = (i / 128) * 2 - 1;
118
- }
119
- font.samples.push(sample);
120
-
121
- const gZone = new BasicInstrumentZone();
122
- gZone.isGlobal = true;
123
- gZone.generators.push(new Generator(generatorTypes.initialAttenuation, 375));
124
- gZone.generators.push(new Generator(generatorTypes.releaseVolEnv, -1000));
125
- gZone.generators.push(new Generator(generatorTypes.sampleModes, 1));
126
-
127
- const zone1 = new BasicInstrumentZone();
128
- zone1.sample = sample;
129
-
130
- const zone2 = new BasicInstrumentZone();
131
- zone2.sample = sample;
132
- zone2.generators.push(new Generator(generatorTypes.fineTune, -9));
133
-
134
-
135
- const inst = new BasicInstrument();
136
- inst.instrumentName = "Saw Wave";
137
- inst.instrumentZones.push(gZone);
138
- inst.instrumentZones.push(zone1);
139
- inst.instrumentZones.push(zone2);
140
- font.instruments.push(inst);
141
-
142
- const pZone = new BasicPresetZone();
143
- pZone.instrument = inst;
144
-
145
- const preset = new BasicPreset(font);
146
- preset.presetName = "Saw Wave";
147
- preset.presetZones.push(pZone);
148
- font.presets.push(preset);
149
-
150
- font.soundFontInfo["ifil"] = "2.1";
151
- font.soundFontInfo["isng"] = "EMU8000";
152
- font.soundFontInfo["INAM"] = "Dummy";
153
- font._parseInternal();
154
- return font.write().buffer;
155
- }
156
-
157
- /**
158
- * parses the bank after loading is done
159
- * @protected
160
- */
161
- _parseInternal()
162
- {
163
- this.isXGBank = false;
164
- // definitions for XG:
165
- // at least one preset with bank 127, 126 or 120
166
- // MUST be a valid XG bank.
167
- // allowed banks: (see XG specification)
168
- // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 24,
169
- // 25, 27, 28, 29, 30, 31, 32, 33, 40, 41, 48, 56, 57, 58,
170
- // 64, 65, 66, 126, 127
171
- const allowedPrograms = new Set([
172
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 24,
173
- 25, 27, 28, 29, 30, 31, 32, 33, 40, 41, 48, 56, 57, 58,
174
- 64, 65, 66, 126, 127
175
- ]);
176
- for (const preset of this.presets)
177
- {
178
- if (isXGDrums(preset.bank))
179
- {
180
- this.isXGBank = true;
181
- if (!allowedPrograms.has(preset.program))
182
- {
183
- // not valid!
184
- this.isXGBank = false;
185
- SpessaSynthInfo(
186
- `%cThis bank is not valid XG. Preset %c${preset.bank}:${preset.program}%c is not a valid XG drum. XG mode will use presets on bank 128.`,
187
- consoleColors.info,
188
- consoleColors.value,
189
- consoleColors.info
190
- );
191
- break;
192
- }
193
- }
194
- }
195
- }
196
-
197
- /**
198
- * Trims a sound bank to only contain samples in a given MIDI file
199
- * @param mid {BasicMIDI} - the MIDI file
200
- */
201
- trimSoundBank(mid)
202
- {
203
- const soundfont = this;
204
-
205
- /**
206
- * @param instrument {Instrument}
207
- * @param combos {{key: number, velocity: number}[]}
208
- * @returns {number}
209
- */
210
- function trimInstrumentZones(instrument, combos)
211
- {
212
- let trimmedIZones = 0;
213
- for (let iZoneIndex = 0; iZoneIndex < instrument.instrumentZones.length; iZoneIndex++)
214
- {
215
- const iZone = instrument.instrumentZones[iZoneIndex];
216
- if (iZone.isGlobal)
217
- {
218
- continue;
219
- }
220
- const iKeyRange = iZone.keyRange;
221
- const iVelRange = iZone.velRange;
222
- let isIZoneUsed = false;
223
- for (const iCombo of combos)
224
- {
225
- if (
226
- (iCombo.key >= iKeyRange.min && iCombo.key <= iKeyRange.max) &&
227
- (iCombo.velocity >= iVelRange.min && iCombo.velocity <= iVelRange.max)
228
- )
229
- {
230
- isIZoneUsed = true;
231
- break;
232
- }
233
- }
234
- if (!isIZoneUsed)
235
- {
236
- SpessaSynthInfo(
237
- `%c${iZone.sample.sampleName} %cremoved from %c${instrument.instrumentName}%c. Use count: %c${iZone.useCount - 1}`,
238
- consoleColors.recognized,
239
- consoleColors.info,
240
- consoleColors.recognized,
241
- consoleColors.info,
242
- consoleColors.recognized
243
- );
244
- if (instrument.safeDeleteZone(iZoneIndex))
245
- {
246
- trimmedIZones++;
247
- iZoneIndex--;
248
- SpessaSynthInfo(
249
- `%c${iZone.sample.sampleName} %cdeleted`,
250
- consoleColors.recognized,
251
- consoleColors.info
252
- );
253
- }
254
- if (iZone.sample.useCount < 1)
255
- {
256
- soundfont.deleteSample(iZone.sample);
257
- }
258
- }
259
-
260
- }
261
- return trimmedIZones;
262
- }
263
-
264
- SpessaSynthGroup(
265
- "%cTrimming soundfont...",
266
- consoleColors.info
267
- );
268
- const usedProgramsAndKeys = mid.getUsedProgramsAndKeys(soundfont);
269
-
270
- SpessaSynthGroupCollapsed(
271
- "%cModifying soundfont...",
272
- consoleColors.info
273
- );
274
- SpessaSynthInfo("Detected keys for midi:", usedProgramsAndKeys);
275
- // modify the soundfont to only include programs and samples that are used
276
- for (let presetIndex = 0; presetIndex < soundfont.presets.length; presetIndex++)
277
- {
278
- const p = soundfont.presets[presetIndex];
279
- const string = p.bank + ":" + p.program;
280
- const used = usedProgramsAndKeys[string];
281
- if (used === undefined)
282
- {
283
- SpessaSynthInfo(
284
- `%cDeleting preset %c${p.presetName}%c and its zones`,
285
- consoleColors.info,
286
- consoleColors.recognized,
287
- consoleColors.info
288
- );
289
- soundfont.deletePreset(p);
290
- presetIndex--;
291
- }
292
- else
293
- {
294
- const combos = [...used].map(s =>
295
- {
296
- const split = s.split("-");
297
- return {
298
- key: parseInt(split[0]),
299
- velocity: parseInt(split[1])
300
- };
301
- });
302
- SpessaSynthGroupCollapsed(
303
- `%cTrimming %c${p.presetName}`,
304
- consoleColors.info,
305
- consoleColors.recognized
306
- );
307
- SpessaSynthInfo(`Keys for ${p.presetName}:`, combos);
308
- let trimmedZones = 0;
309
- // clean the preset to only use zones that are used
310
- for (let zoneIndex = 0; zoneIndex < p.presetZones.length; zoneIndex++)
311
- {
312
- const zone = p.presetZones[zoneIndex];
313
- if (zone.isGlobal)
314
- {
315
- continue;
316
- }
317
- const keyRange = zone.keyRange;
318
- const velRange = zone.velRange;
319
- // check if any of the combos matches the zone
320
- let isZoneUsed = false;
321
- for (const combo of combos)
322
- {
323
- if (
324
- (combo.key >= keyRange.min && combo.key <= keyRange.max) &&
325
- (combo.velocity >= velRange.min && combo.velocity <= velRange.max)
326
- )
327
- {
328
- // zone is used, trim the instrument zones
329
- isZoneUsed = true;
330
- const trimmedIZones = trimInstrumentZones(zone.instrument, combos);
331
- SpessaSynthInfo(
332
- `%cTrimmed off %c${trimmedIZones}%c zones from %c${zone.instrument.instrumentName}`,
333
- consoleColors.info,
334
- consoleColors.recognized,
335
- consoleColors.info,
336
- consoleColors.recognized
337
- );
338
- break;
339
- }
340
- }
341
- if (!isZoneUsed)
342
- {
343
- trimmedZones++;
344
- p.deleteZone(zoneIndex);
345
- if (zone.instrument.useCount < 1)
346
- {
347
- soundfont.deleteInstrument(zone.instrument);
348
- }
349
- zoneIndex--;
350
- }
351
- }
352
- SpessaSynthInfo(
353
- `%cTrimmed off %c${trimmedZones}%c zones from %c${p.presetName}`,
354
- consoleColors.info,
355
- consoleColors.recognized,
356
- consoleColors.info,
357
- consoleColors.recognized
358
- );
359
- SpessaSynthGroupEnd();
360
- }
361
- }
362
- soundfont.removeUnusedElements();
363
-
364
- soundfont.soundFontInfo["ICMT"] = `NOTE: This soundfont was trimmed by SpessaSynth to only contain presets used in "${mid.midiName}"\n\n`
365
- + soundfont.soundFontInfo["ICMT"];
366
-
367
- SpessaSynthInfo(
368
- "%cSoundfont modified!",
369
- consoleColors.recognized
370
- );
371
- SpessaSynthGroupEnd();
372
- SpessaSynthGroupEnd();
373
- }
374
-
375
- removeUnusedElements()
376
- {
377
- this.instruments.forEach(i =>
378
- {
379
- if (i.useCount < 1)
380
- {
381
- i.instrumentZones.forEach(z =>
382
- {
383
- if (!z.isGlobal)
384
- {
385
- z.sample.useCount--;
386
- }
387
- });
388
- }
389
- });
390
- this.instruments = this.instruments.filter(i => i.useCount > 0);
391
- this.samples = this.samples.filter(s => s.useCount > 0);
392
- }
393
-
394
- /**
395
- * @param instrument {BasicInstrument}
396
- */
397
- deleteInstrument(instrument)
398
- {
399
- if (instrument.useCount > 0)
400
- {
401
- throw new Error(`Cannot delete an instrument that has ${instrument.useCount} usages.`);
402
- }
403
- this.instruments.splice(this.instruments.indexOf(instrument), 1);
404
- instrument.deleteInstrument();
405
- this.removeUnusedElements();
406
- }
407
-
408
- /**
409
- * @param preset {BasicPreset}
410
- */
411
- deletePreset(preset)
412
- {
413
- preset.deletePreset();
414
- this.presets.splice(this.presets.indexOf(preset), 1);
415
- this.removeUnusedElements();
416
- }
417
-
418
- /**
419
- * @param sample {BasicSample}
420
- */
421
- deleteSample(sample)
422
- {
423
- if (sample.useCount > 0)
424
- {
425
- throw new Error(`Cannot delete sample that has ${sample.useCount} usages.`);
426
- }
427
- this.samples.splice(this.samples.indexOf(sample), 1);
428
- this.removeUnusedElements();
429
- }
430
-
431
- /**
432
- * Get the appropriate preset, undefined if not found
433
- * @param bankNr {number}
434
- * @param programNr {number}
435
- * @param allowXGDrums {boolean} if true, allows XG drum banks (120, 126 and 127) as drum preset
436
- * @return {BasicPreset}
437
- */
438
- getPresetNoFallback(bankNr, programNr, allowXGDrums = false)
439
- {
440
- const isDrum = bankNr === 128 || (allowXGDrums && isXGDrums(bankNr));
441
- // check for exact match
442
- let p;
443
- if (isDrum)
444
- {
445
- p = this.presets.find(p => p.bank === bankNr && p.isDrumPreset(allowXGDrums) && p.program === programNr);
446
- }
447
- else
448
- {
449
- p = this.presets.find(p => p.bank === bankNr && p.program === programNr);
450
- }
451
- if (p)
452
- {
453
- return p;
454
- }
455
- // no match...
456
- if (isDrum)
457
- {
458
- if (allowXGDrums)
459
- {
460
- // try any drum preset with matching program?
461
- const p = this.presets.find(p => p.isDrumPreset(allowXGDrums) && p.program === programNr);
462
- if (p)
463
- {
464
- return p;
465
- }
466
- }
467
- }
468
- return undefined;
469
- }
470
-
471
- /**
472
- * Get the appropriate preset
473
- * @param bankNr {number}
474
- * @param programNr {number}
475
- * @param allowXGDrums {boolean} if true, allows XG drum banks (120, 126 and 127) as drum preset
476
- * @returns {BasicPreset}
477
- */
478
- getPreset(bankNr, programNr, allowXGDrums = false)
479
- {
480
- const isDrums = bankNr === 128 || (allowXGDrums && isXGDrums(bankNr));
481
- // check for exact match
482
- let preset;
483
- // only allow drums if the preset is considered to be a drum preset
484
- if (isDrums)
485
- {
486
- preset = this.presets.find(p => p.bank === bankNr && p.isDrumPreset(allowXGDrums) && p.program === programNr);
487
- }
488
- else
489
- {
490
- preset = this.presets.find(p => p.bank === bankNr && p.program === programNr);
491
- }
492
- if (preset)
493
- {
494
- return preset;
495
- }
496
- // no match...
497
- if (isDrums)
498
- {
499
- // drum preset: find any preset with bank 128
500
- preset = this.presets.find(p => p.isDrumPreset(allowXGDrums) && p.program === programNr);
501
- if (!preset)
502
- {
503
- // only allow 128, otherwise it would default to XG SFX
504
- preset = this.presets.find(p => p.isDrumPreset(allowXGDrums));
505
- }
506
- }
507
- else
508
- {
509
- // non-drum preset: find any preset with the given program that is not a drum preset
510
- preset = this.presets.find(p => p.program === programNr && !p.isDrumPreset(allowXGDrums));
511
- }
512
- if (preset)
513
- {
514
- SpessaSynthWarn(
515
- `%cPreset ${bankNr}.${programNr} not found. Replaced with %c${preset.presetName} (${preset.bank}.${preset.program})`,
516
- consoleColors.warn,
517
- consoleColors.recognized
518
- );
519
- }
520
-
521
- // no preset, use the first one available
522
- if (!preset)
523
- {
524
- SpessaSynthWarn(`Preset ${programNr} not found. Defaulting to`, this.presets[0].presetName);
525
- preset = this.presets[0];
526
- }
527
- return preset;
528
- }
529
-
530
- /**
531
- * gets preset by name
532
- * @param presetName {string}
533
- * @returns {BasicPreset}
534
- */
535
- getPresetByName(presetName)
536
- {
537
- let preset = this.presets.find(p => p.presetName === presetName);
538
- if (!preset)
539
- {
540
- SpessaSynthWarn("Preset not found. Defaulting to:", this.presets[0].presetName);
541
- preset = this.presets[0];
542
- }
543
- return preset;
544
- }
545
-
546
- /**
547
- * @param error {string}
548
- */
549
- parsingError(error)
550
- {
551
- throw new Error(`SF parsing error: ${error} The file may be corrupted.`);
552
- }
553
-
554
- destroySoundBank()
555
- {
556
- delete this.presets;
557
- delete this.instruments;
558
- delete this.samples;
559
- }
560
- }
561
-
562
- BasicSoundBank.prototype.write = write;
563
- BasicSoundBank.prototype.writeDLS = writeDLS;
564
-
565
- export { BasicSoundBank };
@@ -1,64 +0,0 @@
1
- /**
2
- * @typedef {Object} SoundFontRange
3
- * @property {number} min - the minimum midi note
4
- * @property {number} max - the maximum midi note
5
- */
6
-
7
- export class BasicZone
8
- {
9
- /**
10
- * The zone's velocity range
11
- * min -1 means that it is a default value
12
- * @type {SoundFontRange}
13
- */
14
- velRange = { min: -1, max: 127 };
15
-
16
- /**
17
- * The zone's key range
18
- * min -1 means that it is a default value
19
- * @type {SoundFontRange}
20
- */
21
- keyRange = { min: -1, max: 127 };
22
- /**
23
- * Indicates if the zone is global
24
- * @type {boolean}
25
- */
26
- isGlobal = false;
27
- /**
28
- * The zone's generators
29
- * @type {Generator[]}
30
- */
31
- generators = [];
32
- /**
33
- * The zone's modulators
34
- * @type {Modulator[]}
35
- */
36
- modulators = [];
37
-
38
- /**
39
- * @returns {boolean}
40
- */
41
- get hasKeyRange()
42
- {
43
- return this.keyRange.min !== -1;
44
- }
45
-
46
- /**
47
- * @returns {boolean}
48
- */
49
- get hasVelRange()
50
- {
51
- return this.velRange.min !== -1;
52
- }
53
-
54
- /**
55
- * @param generatorType {generatorTypes}
56
- * @param notFoundValue {number}
57
- * @returns {number}
58
- */
59
- getGeneratorValue(generatorType, notFoundValue)
60
- {
61
- return this.generators.find(g => g.generatorType === generatorType)?.generatorValue ?? notFoundValue;
62
- }
63
- }
64
-
@@ -1,43 +0,0 @@
1
- import { BasicZone } from "./basic_zone.js";
2
-
3
- export class BasicInstrumentZone extends BasicZone
4
- {
5
- /**
6
- * Zone's sample. Undefined if global
7
- * @type {BasicSample|undefined}
8
- */
9
- sample = undefined;
10
- /**
11
- * The zone's use count
12
- * @type {number}
13
- */
14
- useCount = 0;
15
-
16
- deleteZone()
17
- {
18
- this.useCount--;
19
- if (this.isGlobal)
20
- {
21
- return;
22
- }
23
- this.sample.useCount--;
24
- }
25
- }
26
-
27
- export class BasicPresetZone extends BasicZone
28
- {
29
- /**
30
- * Zone's instrument. Undefined if global
31
- * @type {BasicInstrument|undefined}
32
- */
33
- instrument = undefined;
34
-
35
- deleteZone()
36
- {
37
- if (this.isGlobal)
38
- {
39
- return;
40
- }
41
- this.instrument.removeUseCount();
42
- }
43
- }