spessasynth_core 3.26.17 → 3.26.18

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 (60) hide show
  1. package/index.js +5 -3
  2. package/package.json +1 -1
  3. package/src/externals/README.md +6 -0
  4. package/src/sequencer/README.md +5 -1
  5. package/src/soundfont/README.md +6 -8
  6. package/src/soundfont/basic_soundfont/basic_global_zone.js +16 -0
  7. package/src/soundfont/basic_soundfont/basic_instrument.js +26 -22
  8. package/src/soundfont/basic_soundfont/basic_instrument_zone.js +35 -0
  9. package/src/soundfont/basic_soundfont/basic_preset.js +45 -42
  10. package/src/soundfont/basic_soundfont/basic_preset_zone.js +30 -0
  11. package/src/soundfont/basic_soundfont/{basic_soundfont.js → basic_soundbank.js} +22 -44
  12. package/src/soundfont/basic_soundfont/basic_zone.js +1 -5
  13. package/src/soundfont/basic_soundfont/generator.js +2 -152
  14. package/src/soundfont/basic_soundfont/generator_types.js +151 -0
  15. package/src/soundfont/basic_soundfont/modulator.js +217 -65
  16. package/src/soundfont/basic_soundfont/write_dls/art2.js +3 -2
  17. package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +25 -42
  18. package/src/soundfont/basic_soundfont/write_dls/ins.js +11 -27
  19. package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +2 -2
  20. package/src/soundfont/basic_soundfont/write_dls/rgn2.js +2 -2
  21. package/src/soundfont/basic_soundfont/write_sf2/ibag.js +22 -19
  22. package/src/soundfont/basic_soundfont/write_sf2/igen.js +29 -25
  23. package/src/soundfont/basic_soundfont/write_sf2/imod.js +24 -14
  24. package/src/soundfont/basic_soundfont/write_sf2/inst.js +4 -5
  25. package/src/soundfont/basic_soundfont/write_sf2/pbag.js +21 -18
  26. package/src/soundfont/basic_soundfont/write_sf2/pgen.js +30 -27
  27. package/src/soundfont/basic_soundfont/write_sf2/phdr.js +4 -2
  28. package/src/soundfont/basic_soundfont/write_sf2/pmod.js +25 -15
  29. package/src/soundfont/dls/articulator_converter.js +9 -3
  30. package/src/soundfont/dls/dls_preset.js +2 -3
  31. package/src/soundfont/dls/dls_soundfont.js +1 -1
  32. package/src/soundfont/dls/dls_sources.js +7 -6
  33. package/src/soundfont/dls/dls_zone.js +4 -5
  34. package/src/soundfont/dls/read_articulation.js +2 -1
  35. package/src/soundfont/dls/read_instrument.js +3 -6
  36. package/src/soundfont/dls/read_lart.js +1 -1
  37. package/src/soundfont/dls/read_region.js +2 -1
  38. package/src/soundfont/read_sf2/instruments.js +10 -1
  39. package/src/soundfont/read_sf2/modulators.js +10 -23
  40. package/src/soundfont/read_sf2/presets.js +10 -1
  41. package/src/soundfont/read_sf2/soundfont.js +1 -2
  42. package/src/soundfont/read_sf2/zones.js +30 -14
  43. package/src/synthetizer/README.md +3 -3
  44. package/src/synthetizer/audio_engine/README.md +1 -1
  45. package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +1 -1
  46. package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +11 -3
  47. package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +1 -1
  48. package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +1 -1
  49. package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +1 -1
  50. package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +1 -1
  51. package/src/synthetizer/audio_engine/engine_components/voice.js +7 -10
  52. package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +2 -1
  53. package/src/synthetizer/audio_engine/engine_methods/data_entry/awe32.js +1 -1
  54. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +7 -0
  55. package/src/synthetizer/audio_engine/engine_methods/note_on.js +1 -1
  56. package/src/synthetizer/audio_engine/engine_methods/render_voice.js +1 -1
  57. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +1 -1
  58. package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +2 -1
  59. package/src/utils/README.md +5 -2
  60. package/src/soundfont/basic_soundfont/basic_zones.js +0 -43
@@ -1,11 +1,16 @@
1
- import { generatorTypes, MAX_GENERATOR } from "./generator.js";
2
1
  import { midiControllers } from "../../midi/midi_message.js";
2
+ import { generatorTypes, MAX_GENERATOR } from "./generator_types.js";
3
3
 
4
4
  /**
5
5
  * modulators.js
6
6
  * purpose: parses soundfont modulators and the source enums, also includes the default modulators list
7
7
  **/
8
8
 
9
+ export const MOD_BYTE_SIZE = 10;
10
+
11
+ /**
12
+ * @enum {number}
13
+ */
9
14
  export const modulatorSources = {
10
15
  noController: 0,
11
16
  noteOnVelocity: 2,
@@ -17,6 +22,11 @@ export const modulatorSources = {
17
22
  link: 127
18
23
 
19
24
  };
25
+
26
+ /**
27
+ *
28
+ * @enum {number}
29
+ */
20
30
  export const modulatorCurveTypes = {
21
31
  linear: 0,
22
32
  concave: 1,
@@ -27,7 +37,7 @@ export const modulatorCurveTypes = {
27
37
  export class Modulator
28
38
  {
29
39
  /**
30
- * The current computed value of this modulator
40
+ * The current computed value of this modulator. Only used in the synthesis engine for local voices
31
41
  * @type {number}
32
42
  */
33
43
  currentValue = 0;
@@ -51,18 +61,123 @@ export class Modulator
51
61
  transformType;
52
62
 
53
63
  /**
54
- * creates a modulator
55
- * @param srcEnum {number}
56
- * @param secSrcEnum {number}
57
- * @param destination {generatorTypes|number}
64
+ * Indicates if the given modulator is chorus or reverb effects modulator.
65
+ * This is done to simulate BASSMIDI effects behavior:
66
+ * - defaults to 1000 transform amount rather than 200
67
+ * - values can be changed, but anything above 200 is 1000
68
+ * (except for values above 1000, they are copied directly)
69
+ * - all values below are multiplied by 5 (200 * 5 = 1000)
70
+ * - still can be disabled if the soundfont has its own modulator curve
71
+ * - this fixes the very low amount of reverb by default and doesn't break soundfonts
72
+ * @type {boolean}
73
+ */
74
+ isEffectModulator = false;
75
+
76
+ /**
77
+ * 1 if the source is bipolar (min is -1, max is 1)
78
+ * otherwise min is 0 and max is 1
79
+ * @type {0|1}
80
+ */
81
+ sourcePolarity;
82
+
83
+ /**
84
+ * 1 if the source is negative (from 1 to 0)
85
+ * @type {0|1}
86
+ */
87
+ sourceDirection;
88
+
89
+ /**
90
+ * 1 if the source uses a MIDI CC
91
+ * @type {0|1}
92
+ */
93
+ sourceUsesCC;
94
+
95
+ /**
96
+ * source index/CC number
97
+ * @type {modulatorSources|midiControllers}
98
+ */
99
+ sourceIndex;
100
+
101
+ /**
102
+ * source curve type
103
+ * @type {modulatorCurveTypes}
104
+ */
105
+ sourceCurveType;
106
+
107
+ /**
108
+ * 1 if the source is bipolar (min is -1, max is 1)
109
+ * otherwise min is 0 and max is 1
110
+ * @type {0|1}
111
+ */
112
+ secSrcPolarity;
113
+
114
+ /**
115
+ * 1 if the source is negative (from 1 to 0)
116
+ * @type {0|1}
117
+ */
118
+ secSrcDirection;
119
+
120
+ /**
121
+ * 1 if the source uses a MIDI CC
122
+ * @type {0|1}
123
+ */
124
+ secSrcUsesCC;
125
+
126
+ /**
127
+ * source index/CC number
128
+ * @type {modulatorSources|midiControllers}
129
+ */
130
+ secSrcIndex;
131
+
132
+ /**
133
+ * source curve type
134
+ * @type {modulatorCurveTypes}
135
+ */
136
+ secSrcCurveType;
137
+
138
+ /**
139
+ * Creates a new SF2 Modulator
140
+ * @param sourceIndex {modulatorSources|midiControllers}
141
+ * @param sourceCurveType {modulatorCurveTypes}
142
+ * @param sourceUsesCC {0|1}
143
+ * @param sourcePolarity {0|1}
144
+ * @param sourceDirection {0|1}
145
+ * @param secSrcIndex {modulatorSources|midiControllers}
146
+ * @param secSrcCurveType {modulatorCurveTypes}
147
+ * @param secSrcUsesCC {0|1}
148
+ * @param secSrcPolarity {0|1}
149
+ * @param secSrcDirection {0|1}
150
+ * @param destination {generatorTypes}
58
151
  * @param amount {number}
59
- * @param transformType {number}
152
+ * @param transformType {0|2}
60
153
  */
61
- constructor(srcEnum, secSrcEnum, destination, amount, transformType)
154
+ constructor(sourceIndex,
155
+ sourceCurveType,
156
+ sourceUsesCC,
157
+ sourcePolarity,
158
+ sourceDirection,
159
+ secSrcIndex,
160
+ secSrcCurveType,
161
+ secSrcUsesCC,
162
+ secSrcPolarity,
163
+ secSrcDirection,
164
+ destination,
165
+ amount,
166
+ transformType)
62
167
  {
63
- const sourceEnum = srcEnum;
168
+ this.sourcePolarity = sourcePolarity;
169
+ this.sourceDirection = sourceDirection;
170
+ this.sourceUsesCC = sourceUsesCC;
171
+ this.sourceIndex = sourceIndex;
172
+ this.sourceCurveType = sourceCurveType;
173
+
174
+ this.secSrcPolarity = secSrcPolarity;
175
+ this.secSrcDirection = secSrcDirection;
176
+ this.secSrcUsesCC = secSrcUsesCC;
177
+ this.secSrcIndex = secSrcIndex;
178
+ this.secSrcCurveType = secSrcCurveType;
179
+
64
180
  this.modulatorDestination = destination;
65
- const secondarySourceEnum = secSrcEnum;
66
181
  this.transformAmount = amount;
67
182
  this.transformType = transformType;
68
183
 
@@ -72,41 +187,6 @@ export class Modulator
72
187
  this.modulatorDestination = generatorTypes.INVALID; // flag as invalid (for linked ones)
73
188
  }
74
189
 
75
- // decode the source
76
- this.sourcePolarity = sourceEnum >> 9 & 1;
77
- this.sourceDirection = sourceEnum >> 8 & 1;
78
- this.sourceUsesCC = sourceEnum >> 7 & 1;
79
- this.sourceIndex = sourceEnum & 127;
80
- this.sourceCurveType = sourceEnum >> 10 & 3;
81
-
82
- // decode the secondary source
83
- this.secSrcPolarity = secondarySourceEnum >> 9 & 1;
84
- this.secSrcDirection = secondarySourceEnum >> 8 & 1;
85
- this.secSrcUsesCC = secondarySourceEnum >> 7 & 1;
86
- this.secSrcIndex = secondarySourceEnum & 127;
87
- this.secSrcCurveType = secondarySourceEnum >> 10 & 3;
88
-
89
- /**
90
- * Indicates if the given modulator is chorus or reverb effects modulator.
91
- * This is done to simulate BASSMIDI effects behavior:
92
- * - defaults to 1000 transform amount rather than 200
93
- * - values can be changed, but anything above 200 is 1000
94
- * (except for values above 1000, they are copied directly)
95
- * - all values below are multiplied by 5 (200 * 5 = 1000)
96
- * - still can be disabled if the soundfont has its own modulator curve
97
- * - this fixes the very low amount of reverb by default and doesn't break soundfonts
98
- * @type {boolean}
99
- */
100
- this.isEffectModulator =
101
- (
102
- sourceEnum === 0x00DB
103
- || sourceEnum === 0x00DD
104
- )
105
- && secondarySourceEnum === 0x0
106
- && (
107
- this.modulatorDestination === generatorTypes.reverbEffectsSend
108
- || this.modulatorDestination === generatorTypes.chorusEffectsSend
109
- );
110
190
  }
111
191
 
112
192
  /**
@@ -116,8 +196,16 @@ export class Modulator
116
196
  static copy(modulator)
117
197
  {
118
198
  return new Modulator(
119
- modulator.getSourceEnum(),
120
- modulator.getSecSrcEnum(),
199
+ modulator.sourceIndex,
200
+ modulator.sourceCurveType,
201
+ modulator.sourceUsesCC,
202
+ modulator.sourcePolarity,
203
+ modulator.sourceDirection,
204
+ modulator.secSrcIndex,
205
+ modulator.secSrcCurveType,
206
+ modulator.secSrcUsesCC,
207
+ modulator.secSrcPolarity,
208
+ modulator.secSrcDirection,
121
209
  modulator.modulatorDestination,
122
210
  modulator.transformAmount,
123
211
  modulator.transformType
@@ -174,7 +262,7 @@ export class Modulator
174
262
 
175
263
  let secSrcString = getKeyByValue(modulatorCurveTypes, mod.secSrcCurveType);
176
264
  secSrcString += mod.secSrcPolarity === 0 ? " unipolar " : " bipolar ";
177
- secSrcString += mod.secSrcCurveType === 0 ? "forwards " : "backwards ";
265
+ secSrcString += mod.secSrcDirection === 0 ? "forwards " : "backwards ";
178
266
  if (mod.secSrcUsesCC)
179
267
  {
180
268
  secSrcString += getKeyByValue(midiControllers, mod.secSrcIndex);
@@ -222,8 +310,16 @@ export class Modulator
222
310
  sumTransform(modulator)
223
311
  {
224
312
  return new Modulator(
225
- this.getSourceEnum(),
226
- this.getSecSrcEnum(),
313
+ this.sourceIndex,
314
+ this.sourceCurveType,
315
+ this.sourceUsesCC,
316
+ this.sourcePolarity,
317
+ this.sourceDirection,
318
+ this.secSrcIndex,
319
+ this.secSrcCurveType,
320
+ this.secSrcUsesCC,
321
+ this.secSrcPolarity,
322
+ this.secSrcDirection,
227
323
  this.modulatorDestination,
228
324
  this.transformAmount + modulator.transformAmount,
229
325
  this.transformType
@@ -231,6 +327,62 @@ export class Modulator
231
327
  }
232
328
  }
233
329
 
330
+ export class DecodedModulator extends Modulator
331
+ {
332
+ /**
333
+ * reads an SF2 modulator
334
+ * @param sourceEnum {number} SF2 source enum
335
+ * @param secondarySourceEnum {number} SF2 secondary source enum
336
+ * @param destination {generatorTypes|number} destination
337
+ * @param amount {number} amount
338
+ * @param transformType {number} transform type
339
+ */
340
+ constructor(sourceEnum, secondarySourceEnum, destination, amount, transformType)
341
+ {
342
+ // decode the source
343
+ const sourcePolarity = sourceEnum >> 9 & 1;
344
+ const sourceDirection = sourceEnum >> 8 & 1;
345
+ const sourceUsesCC = sourceEnum >> 7 & 1;
346
+ const sourceIndex = /** @type {modulatorSources} **/ sourceEnum & 127;
347
+ const sourceCurveType = /** @type {modulatorCurveTypes} **/ sourceEnum >> 10 & 3;
348
+
349
+ // decode the secondary source
350
+ const secSrcPolarity = secondarySourceEnum >> 9 & 1;
351
+ const secSrcDirection = secondarySourceEnum >> 8 & 1;
352
+ const secSrcUsesCC = secondarySourceEnum >> 7 & 1;
353
+ const secSrcIndex = /** @type {modulatorSources} **/ secondarySourceEnum & 127;
354
+ const secSrcCurveType = /** @type {modulatorCurveTypes} **/ secondarySourceEnum >> 10 & 3;
355
+
356
+ super(
357
+ sourceIndex,
358
+ sourceCurveType,
359
+ sourceUsesCC,
360
+ sourcePolarity,
361
+ sourceDirection,
362
+ secSrcIndex,
363
+ secSrcCurveType,
364
+ secSrcUsesCC,
365
+ secSrcPolarity,
366
+ secSrcDirection,
367
+ destination,
368
+ amount,
369
+ transformType
370
+ );
371
+
372
+
373
+ this.isEffectModulator =
374
+ (
375
+ sourceEnum === 0x00DB
376
+ || sourceEnum === 0x00DD
377
+ )
378
+ && secondarySourceEnum === 0x0
379
+ && (
380
+ this.modulatorDestination === generatorTypes.reverbEffectsSend
381
+ || this.modulatorDestination === generatorTypes.chorusEffectsSend
382
+ );
383
+ }
384
+ }
385
+
234
386
  export const DEFAULT_ATTENUATION_MOD_AMOUNT = 960;
235
387
  export const DEFAULT_ATTENUATION_MOD_CURVE_TYPE = modulatorCurveTypes.concave;
236
388
 
@@ -241,7 +393,7 @@ export function getModSourceEnum(curveType, polarity, direction, isCC, index)
241
393
 
242
394
  const soundFontModulators = [
243
395
  // vel to attenuation
244
- new Modulator(
396
+ new DecodedModulator(
245
397
  getModSourceEnum(
246
398
  DEFAULT_ATTENUATION_MOD_CURVE_TYPE,
247
399
  0,
@@ -256,10 +408,10 @@ const soundFontModulators = [
256
408
  ),
257
409
 
258
410
  // mod wheel to vibrato
259
- new Modulator(0x0081, 0x0, generatorTypes.vibLfoToPitch, 50, 0),
411
+ new DecodedModulator(0x0081, 0x0, generatorTypes.vibLfoToPitch, 50, 0),
260
412
 
261
413
  // vol to attenuation
262
- new Modulator(
414
+ new DecodedModulator(
263
415
  getModSourceEnum(
264
416
  DEFAULT_ATTENUATION_MOD_CURVE_TYPE,
265
417
  0,
@@ -274,17 +426,17 @@ const soundFontModulators = [
274
426
  ),
275
427
 
276
428
  // channel pressure to vibrato
277
- new Modulator(0x000D, 0x0, generatorTypes.vibLfoToPitch, 50, 0),
429
+ new DecodedModulator(0x000D, 0x0, generatorTypes.vibLfoToPitch, 50, 0),
278
430
 
279
431
  // pitch wheel to tuning
280
- new Modulator(0x020E, 0x0010, generatorTypes.fineTune, 12700, 0),
432
+ new DecodedModulator(0x020E, 0x0010, generatorTypes.fineTune, 12700, 0),
281
433
 
282
434
  // pan to uhh, pan
283
435
  // amount is 500 instead of 1000, see #59
284
- new Modulator(0x028A, 0x0, generatorTypes.pan, 500, 0),
436
+ new DecodedModulator(0x028A, 0x0, generatorTypes.pan, 500, 0),
285
437
 
286
438
  // expression to attenuation
287
- new Modulator(
439
+ new DecodedModulator(
288
440
  getModSourceEnum(
289
441
  DEFAULT_ATTENUATION_MOD_CURVE_TYPE,
290
442
  0,
@@ -299,16 +451,16 @@ const soundFontModulators = [
299
451
  ),
300
452
 
301
453
  // reverb effects to send
302
- new Modulator(0x00DB, 0x0, generatorTypes.reverbEffectsSend, 200, 0),
454
+ new DecodedModulator(0x00DB, 0x0, generatorTypes.reverbEffectsSend, 200, 0),
303
455
 
304
456
  // chorus effects to send
305
- new Modulator(0x00DD, 0x0, generatorTypes.chorusEffectsSend, 200, 0)
457
+ new DecodedModulator(0x00DD, 0x0, generatorTypes.chorusEffectsSend, 200, 0)
306
458
  ];
307
459
 
308
460
  const customModulators = [
309
461
  // custom modulators heck yeah
310
462
  // poly pressure to vibrato
311
- new Modulator(
463
+ new DecodedModulator(
312
464
  getModSourceEnum(modulatorCurveTypes.linear, 0, 0, 0, modulatorSources.polyPressure),
313
465
  0x0,
314
466
  generatorTypes.vibLfoToPitch,
@@ -317,7 +469,7 @@ const customModulators = [
317
469
  ),
318
470
 
319
471
  // cc 92 (tremolo) to modLFO volume
320
- new Modulator(
472
+ new DecodedModulator(
321
473
  getModSourceEnum(
322
474
  modulatorCurveTypes.linear,
323
475
  0,
@@ -332,7 +484,7 @@ const customModulators = [
332
484
  ),
333
485
 
334
486
  // cc 73 (attack time) to volEnv attack
335
- new Modulator(
487
+ new DecodedModulator(
336
488
  getModSourceEnum(
337
489
  modulatorCurveTypes.convex,
338
490
  1,
@@ -347,7 +499,7 @@ const customModulators = [
347
499
  ),
348
500
 
349
501
  // cc 72 (release time) to volEnv release
350
- new Modulator(
502
+ new DecodedModulator(
351
503
  getModSourceEnum(
352
504
  modulatorCurveTypes.linear,
353
505
  1,
@@ -362,7 +514,7 @@ const customModulators = [
362
514
  ),
363
515
 
364
516
  // cc 74 (brightness) to filterFc
365
- new Modulator(
517
+ new DecodedModulator(
366
518
  getModSourceEnum(
367
519
  modulatorCurveTypes.linear,
368
520
  1,
@@ -377,7 +529,7 @@ const customModulators = [
377
529
  ),
378
530
 
379
531
  // cc 71 (filter Q) to filter Q
380
- new Modulator(
532
+ new DecodedModulator(
381
533
  getModSourceEnum(
382
534
  modulatorCurveTypes.linear,
383
535
  1,
@@ -1,7 +1,7 @@
1
1
  import { getDLSArticulatorFromSf2Generator, getDLSArticulatorFromSf2Modulator } from "./modulator_converter.js";
2
2
  import { writeRIFFOddSize } from "../riff_chunk.js";
3
3
  import { combineArrays, IndexedByteArray } from "../../../utils/indexed_array.js";
4
- import { Generator, generatorTypes } from "../generator.js";
4
+ import { Generator } from "../generator.js";
5
5
  import { writeDword } from "../../../utils/byte_functions/little_endian.js";
6
6
  import { consoleColors } from "../../../utils/other.js";
7
7
  import { SpessaSynthInfo, SpessaSynthWarn } from "../../../utils/loggin.js";
@@ -12,6 +12,7 @@ import {
12
12
  DLS_1_NO_VIBRATO_MOD,
13
13
  DLS_1_NO_VIBRATO_PRESSURE
14
14
  } from "../../dls/dls_sources.js";
15
+ import { generatorTypes } from "../generator_types.js";
15
16
 
16
17
  const invalidGeneratorTypes = new Set([
17
18
  generatorTypes.sampleModes,
@@ -34,7 +35,7 @@ const invalidGeneratorTypes = new Set([
34
35
  ]);
35
36
 
36
37
  /**
37
- * @param zone {BasicInstrumentZone}
38
+ * @param zone {BasicZone}
38
39
  * @returns {IndexedByteArray}
39
40
  */
40
41
  export function writeArticulator(zone)
@@ -1,6 +1,8 @@
1
1
  import { Modulator } from "../modulator.js";
2
- import { BasicInstrumentZone } from "../basic_zones.js";
3
- import { Generator, generatorLimits, generatorTypes } from "../generator.js";
2
+ import { Generator } from "../generator.js";
3
+ import { generatorLimits, generatorTypes } from "../generator_types.js";
4
+ import { BasicInstrumentZone } from "../basic_instrument_zone.js";
5
+ import { BasicGlobalZone } from "../basic_global_zone.js";
4
6
 
5
7
  const notGlobalizedTypes = new Set([
6
8
  generatorTypes.velRange,
@@ -30,7 +32,7 @@ const notGlobalizedTypes = new Set([
30
32
  * Combines preset zones
31
33
  * @param preset {BasicPreset}
32
34
  * @param globalize {boolean}
33
- * @returns {BasicInstrumentZone[]}
35
+ * @returns {{global: BasicGlobalZone, zones: BasicInstrumentZone[]}}
34
36
  */
35
37
  export function combineZones(preset, globalize = true)
36
38
  {
@@ -75,25 +77,16 @@ export function combineZones(preset, globalize = true)
75
77
  * @type {Modulator[]}
76
78
  */
77
79
  const globalPresetModulators = [];
78
- let globalPresetKeyRange = { min: 0, max: 127 };
79
- let globalPresetVelRange = { min: 0, max: 127 };
80
80
 
81
81
  // find the global zone and apply ranges, generators, and modulators
82
- const globalPresetZone = preset.presetZones.find(z => z.isGlobal);
83
- if (globalPresetZone)
84
- {
85
- globalPresetGenerators.push(...globalPresetZone.generators);
86
- globalPresetModulators.push(...globalPresetZone.modulators);
87
- globalPresetKeyRange = globalPresetZone.keyRange;
88
- globalPresetVelRange = globalPresetZone.velRange;
89
- }
82
+ const globalPresetZone = preset.globalZone;
83
+ globalPresetGenerators.push(...globalPresetZone.generators);
84
+ globalPresetModulators.push(...globalPresetZone.modulators);
85
+ let globalPresetKeyRange = globalPresetZone.keyRange;
86
+ let globalPresetVelRange = globalPresetZone.velRange;
90
87
  // for each non-global preset zone
91
88
  for (const presetZone of preset.presetZones)
92
89
  {
93
- if (presetZone.isGlobal)
94
- {
95
- continue;
96
- }
97
90
  // use global ranges if not provided
98
91
  let presetZoneKeyRange = presetZone.keyRange;
99
92
  if (!presetZone.hasKeyRange)
@@ -110,8 +103,8 @@ export function combineZones(preset, globalize = true)
110
103
  addUnique(presetGenerators, globalPresetGenerators);
111
104
  const presetModulators = [...presetZone.modulators];
112
105
  addUniqueMods(presetModulators, globalPresetModulators);
113
-
114
- const iZones = presetZone.instrument.instrumentZones;
106
+ const instrument = presetZone.instrument;
107
+ const iZones = instrument.instrumentZones;
115
108
  /**
116
109
  * @type {Generator[]}
117
110
  */
@@ -120,23 +113,14 @@ export function combineZones(preset, globalize = true)
120
113
  * @type {Modulator[]}
121
114
  */
122
115
  const globalInstModulators = [];
123
- let globalInstKeyRange = { min: 0, max: 127 };
124
- let globalInstVelRange = { min: 0, max: 127 };
125
- const globalInstZone = iZones.find(z => z.isGlobal);
126
- if (globalInstZone)
127
- {
128
- globalInstGenerators.push(...globalInstZone.generators);
129
- globalInstModulators.push(...globalInstZone.modulators);
130
- globalInstKeyRange = globalInstZone.keyRange;
131
- globalInstVelRange = globalInstZone.velRange;
132
- }
116
+ const globalInstZone = instrument.globalZone;
117
+ globalInstGenerators.push(...globalInstZone.generators);
118
+ globalInstModulators.push(...globalInstZone.modulators);
119
+ let globalInstKeyRange = globalInstZone.keyRange;
120
+ let globalInstVelRange = globalInstZone.velRange;
133
121
  // for each non-global instrument zone
134
122
  for (const instZone of iZones)
135
123
  {
136
- if (instZone.isGlobal)
137
- {
138
- continue;
139
- }
140
124
  // use global ranges if not provided
141
125
  let instZoneKeyRange = instZone.keyRange;
142
126
  if (!instZone.hasKeyRange)
@@ -236,20 +220,17 @@ export function combineZones(preset, globalize = true)
236
220
  {
237
221
  zone.velRange.min = -1;
238
222
  }
239
- zone.isGlobal = false;
240
- zone.sample = instZone.sample;
223
+ zone.setSample(instZone.sample);
241
224
  zone.generators = finalGenList;
242
225
  zone.modulators = finalModList;
243
226
  finalZones.push(zone);
244
227
  }
245
228
  }
246
-
229
+ const globalZone = new BasicGlobalZone();
247
230
  if (globalize)
248
231
  {
249
232
  // create a global zone and add repeating generators to it
250
233
  // also modulators
251
- const globalZone = new BasicInstrumentZone();
252
- globalZone.isGlobal = true;
253
234
  // iterate over every type of generator
254
235
  for (let checkedType = 0; checkedType < 58; checkedType++)
255
236
  {
@@ -356,14 +337,14 @@ export function combineZones(preset, globalize = true)
356
337
  }
357
338
 
358
339
  // globalize only modulators that exist in all zones
359
- const firstZone = finalZones.find(z => !z.isGlobal);
340
+ const firstZone = finalZones[0];
360
341
  const modulators = firstZone.modulators.map(m => Modulator.copy(m));
361
342
  for (const checkedModulator of modulators)
362
343
  {
363
344
  let existsForAllZones = true;
364
345
  for (const zone of finalZones)
365
346
  {
366
- if (zone.isGlobal || !existsForAllZones)
347
+ if (!existsForAllZones)
367
348
  {
368
349
  continue;
369
350
  }
@@ -394,7 +375,9 @@ export function combineZones(preset, globalize = true)
394
375
  }
395
376
  }
396
377
  }
397
- finalZones.splice(0, 0, globalZone);
398
378
  }
399
- return finalZones;
379
+ return {
380
+ zones: finalZones,
381
+ global: globalZone
382
+ };
400
383
  }
@@ -22,20 +22,12 @@ export function writeIns(preset)
22
22
  consoleColors.info
23
23
  );
24
24
  // combine preset and instrument zones into a single instrument zone (region) list
25
- const combined = combineZones(preset);
25
+ const { global, zones } = combineZones(preset);
26
26
 
27
- const nonGlobalRegionsCount = combined.reduce((sum, z) =>
28
- {
29
- if (!z.isGlobal)
30
- {
31
- return sum + 1;
32
- }
33
- return sum;
34
- }, 0);
35
27
 
36
28
  // insh: instrument header
37
29
  const inshData = new IndexedByteArray(12);
38
- writeDword(inshData, nonGlobalRegionsCount); // cRegions
30
+ writeDword(inshData, zones.length); // cRegions
39
31
  // bank MSB is in bits 8-14
40
32
  let ulBank = (preset.bank & 127) << 8;
41
33
  // bit 32 means drums
@@ -52,26 +44,18 @@ export function writeIns(preset)
52
44
  );
53
45
 
54
46
  // write global zone
55
- let lar2 = new IndexedByteArray(0);
56
- const globalZone = combined.find(z => z.isGlobal === true);
57
- if (globalZone)
58
- {
59
- const art2 = writeArticulator(globalZone);
60
- lar2 = writeRIFFOddSize(
61
- "lar2",
62
- art2,
63
- false,
64
- true
65
- );
66
- }
47
+ const art2 = writeArticulator(global);
48
+ let lar2 = writeRIFFOddSize(
49
+ "lar2",
50
+ art2,
51
+ false,
52
+ true
53
+ );
67
54
 
68
55
  // write the region list
69
- const lrgnData = combineArrays(combined.reduce((arrs, z) =>
56
+ const lrgnData = combineArrays(zones.reduce((arrs, z) =>
70
57
  {
71
- if (!z.isGlobal)
72
- {
73
- arrs.push(writeDLSRegion.apply(this, [z, globalZone]));
74
- }
58
+ arrs.push(writeDLSRegion.apply(this, [z, global]));
75
59
  return arrs;
76
60
  }, []));
77
61
  const lrgn = writeRIFFOddSize(
@@ -1,14 +1,14 @@
1
1
  import { midiControllers } from "../../../midi/midi_message.js";
2
2
  import { DLSSources } from "../../dls/dls_sources.js";
3
3
  import { modulatorCurveTypes, modulatorSources } from "../modulator.js";
4
- import { generatorTypes } from "../generator.js";
5
4
  import { DLSDestinations } from "../../dls/dls_destinations.js";
6
5
  import { Articulator } from "./articulator.js";
7
6
  import { SpessaSynthWarn } from "../../../utils/loggin.js";
7
+ import { generatorTypes } from "../generator_types.js";
8
8
 
9
9
 
10
10
  /**
11
- * @param cc {boolean}
11
+ * @param cc {0|1}
12
12
  * @param index {number}
13
13
  * @returns {number|undefined}
14
14
  */
@@ -1,13 +1,13 @@
1
1
  import { combineArrays, IndexedByteArray } from "../../../utils/indexed_array.js";
2
2
  import { writeDword, writeWord } from "../../../utils/byte_functions/little_endian.js";
3
- import { generatorTypes } from "../generator.js";
4
3
  import { writeRIFFOddSize } from "../riff_chunk.js";
5
4
  import { writeWavesample } from "./wsmp.js";
6
5
  import { writeArticulator } from "./art2.js";
6
+ import { generatorTypes } from "../generator_types.js";
7
7
 
8
8
  /**
9
9
  * @param zone {BasicInstrumentZone}
10
- * @param globalZone {BasicInstrumentZone}
10
+ * @param globalZone {BasicGlobalZone}
11
11
  * @this {BasicSoundBank}
12
12
  * @returns {IndexedByteArray}
13
13
  */