spessasynth_core 3.26.17 → 3.26.19

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 (62) 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 +53 -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} +96 -55
  12. package/src/soundfont/basic_soundfont/basic_zone.js +73 -5
  13. package/src/soundfont/basic_soundfont/generator.js +4 -163
  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 +28 -45
  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 +33 -29
  23. package/src/soundfont/basic_soundfont/write_sf2/imod.js +26 -16
  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 +32 -29
  27. package/src/soundfont/basic_soundfont/write_sf2/phdr.js +4 -2
  28. package/src/soundfont/basic_soundfont/write_sf2/pmod.js +26 -16
  29. package/src/soundfont/basic_soundfont/write_sf2/write.js +14 -8
  30. package/src/soundfont/dls/articulator_converter.js +9 -3
  31. package/src/soundfont/dls/dls_preset.js +2 -3
  32. package/src/soundfont/dls/dls_soundfont.js +2 -3
  33. package/src/soundfont/dls/dls_sources.js +7 -6
  34. package/src/soundfont/dls/dls_zone.js +13 -16
  35. package/src/soundfont/dls/read_articulation.js +2 -1
  36. package/src/soundfont/dls/read_instrument.js +7 -10
  37. package/src/soundfont/dls/read_lart.js +5 -5
  38. package/src/soundfont/dls/read_region.js +3 -3
  39. package/src/soundfont/read_sf2/instruments.js +10 -1
  40. package/src/soundfont/read_sf2/modulators.js +10 -23
  41. package/src/soundfont/read_sf2/presets.js +10 -1
  42. package/src/soundfont/read_sf2/soundfont.js +3 -5
  43. package/src/soundfont/read_sf2/zones.js +30 -70
  44. package/src/synthetizer/README.md +3 -3
  45. package/src/synthetizer/audio_engine/README.md +1 -1
  46. package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +20 -19
  47. package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +11 -3
  48. package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +1 -1
  49. package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +1 -1
  50. package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +1 -1
  51. package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +1 -1
  52. package/src/synthetizer/audio_engine/engine_components/voice.js +7 -10
  53. package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +2 -1
  54. package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -4
  55. package/src/synthetizer/audio_engine/engine_methods/data_entry/awe32.js +1 -1
  56. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +7 -0
  57. package/src/synthetizer/audio_engine/engine_methods/note_on.js +1 -1
  58. package/src/synthetizer/audio_engine/engine_methods/render_voice.js +1 -1
  59. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +1 -1
  60. package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +2 -1
  61. package/src/utils/README.md +5 -2
  62. package/src/soundfont/basic_soundfont/basic_zones.js +0 -43
@@ -1,4 +1,4 @@
1
- import { BasicSoundBank } from "../basic_soundfont/basic_soundfont.js";
1
+ import { BasicSoundBank } from "../basic_soundfont/basic_soundbank.js";
2
2
  import { IndexedByteArray } from "../../utils/indexed_array.js";
3
3
  import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from "../../utils/loggin.js";
4
4
  import { consoleColors } from "../../utils/other.js";
@@ -114,8 +114,7 @@ class DLSSoundFont extends BasicSoundBank
114
114
  this.readDLSInstrumentList(instrumentListChunk);
115
115
 
116
116
  // sort presets
117
- this.presets.sort((a, b) => (a.program - b.program) + (a.bank - b.bank));
118
- this._parseInternal();
117
+ this.flush();
119
118
  SpessaSynthInfo(
120
119
  `%cParsing finished! %c"${this.soundFontInfo["INAM"] || "UNNAMED"}"%c has %c${this.presets.length} %cpresets,
121
120
  %c${this.instruments.length}%c instruments and %c${this.samples.length}%c samples.`,
@@ -1,5 +1,6 @@
1
- import { Modulator } from "../basic_soundfont/modulator.js";
2
- import { generatorTypes } from "../basic_soundfont/generator.js";
1
+ import { DecodedModulator } from "../basic_soundfont/modulator.js";
2
+
3
+ import { generatorTypes } from "../basic_soundfont/generator_types.js";
3
4
 
4
5
  /**
5
6
  * @enum {number}
@@ -29,7 +30,7 @@ export const DLSSources = {
29
30
  coarseTune: 0x102
30
31
  };
31
32
 
32
- export const DEFAULT_DLS_REVERB = new Modulator(
33
+ export const DEFAULT_DLS_REVERB = new DecodedModulator(
33
34
  0x00DB,
34
35
  0x0,
35
36
  generatorTypes.reverbEffectsSend,
@@ -37,7 +38,7 @@ export const DEFAULT_DLS_REVERB = new Modulator(
37
38
  0
38
39
  );
39
40
 
40
- export const DEFAULT_DLS_CHORUS = new Modulator(
41
+ export const DEFAULT_DLS_CHORUS = new DecodedModulator(
41
42
  0x00DD,
42
43
  0x0,
43
44
  generatorTypes.chorusEffectsSend,
@@ -45,7 +46,7 @@ export const DEFAULT_DLS_CHORUS = new Modulator(
45
46
  0
46
47
  );
47
48
 
48
- export const DLS_1_NO_VIBRATO_MOD = new Modulator(
49
+ export const DLS_1_NO_VIBRATO_MOD = new DecodedModulator(
49
50
  0x0081,
50
51
  0x0,
51
52
  generatorTypes.vibLfoToPitch,
@@ -53,7 +54,7 @@ export const DLS_1_NO_VIBRATO_MOD = new Modulator(
53
54
  0
54
55
  );
55
56
 
56
- export const DLS_1_NO_VIBRATO_PRESSURE = new Modulator(
57
+ export const DLS_1_NO_VIBRATO_PRESSURE = new DecodedModulator(
57
58
  0x000D,
58
59
  0x0,
59
60
  generatorTypes.vibLfoToPitch,
@@ -1,5 +1,6 @@
1
- import { BasicInstrumentZone } from "../basic_soundfont/basic_zones.js";
2
- import { Generator, generatorTypes } from "../basic_soundfont/generator.js";
1
+ import { Generator } from "../basic_soundfont/generator.js";
2
+ import { generatorTypes } from "../basic_soundfont/generator_types.js";
3
+ import { BasicInstrumentZone } from "../basic_soundfont/basic_instrument_zone.js";
3
4
 
4
5
  export class DLSZone extends BasicInstrumentZone
5
6
  {
@@ -12,7 +13,6 @@ export class DLSZone extends BasicInstrumentZone
12
13
  super();
13
14
  this.keyRange = keyRange;
14
15
  this.velRange = velRange;
15
- this.isGlobal = true;
16
16
  }
17
17
 
18
18
  /**
@@ -36,22 +36,21 @@ export class DLSZone extends BasicInstrumentZone
36
36
  {
37
37
  if (loopingMode !== 0)
38
38
  {
39
- this.generators.push(new Generator(generatorTypes.sampleModes, loopingMode));
39
+ this.addGenerators(new Generator(generatorTypes.sampleModes, loopingMode));
40
40
  }
41
- this.generators.push(new Generator(generatorTypes.initialAttenuation, attenuationCb));
42
- this.isGlobal = false;
41
+ this.addGenerators(new Generator(generatorTypes.initialAttenuation, attenuationCb));
43
42
 
44
43
  // correct tuning if needed
45
44
  samplePitchCorrection -= sample.samplePitchCorrection;
46
45
  const coarseTune = Math.trunc(samplePitchCorrection / 100);
47
46
  if (coarseTune !== 0)
48
47
  {
49
- this.generators.push(new Generator(generatorTypes.coarseTune, coarseTune));
48
+ this.addGenerators(new Generator(generatorTypes.coarseTune, coarseTune));
50
49
  }
51
50
  const fineTune = samplePitchCorrection - (coarseTune * 100);
52
51
  if (fineTune !== 0)
53
52
  {
54
- this.generators.push(new Generator(generatorTypes.fineTune, fineTune));
53
+ this.addGenerators(new Generator(generatorTypes.fineTune, fineTune));
55
54
  }
56
55
 
57
56
  // correct loop if needed
@@ -62,34 +61,32 @@ export class DLSZone extends BasicInstrumentZone
62
61
  if (diffStart !== 0)
63
62
  {
64
63
  const fine = diffStart % 32768;
65
- this.generators.push(new Generator(generatorTypes.startloopAddrsOffset, fine));
64
+ this.addGenerators(new Generator(generatorTypes.startloopAddrsOffset, fine));
66
65
  // coarse generator uses 32768 samples per step
67
66
  const coarse = Math.trunc(diffStart / 32768);
68
67
  if (coarse !== 0)
69
68
  {
70
- this.generators.push(new Generator(generatorTypes.startloopAddrsCoarseOffset, coarse));
69
+ this.addGenerators(new Generator(generatorTypes.startloopAddrsCoarseOffset, coarse));
71
70
  }
72
71
  }
73
72
  if (diffEnd !== 0)
74
73
  {
75
74
  const fine = diffEnd % 32768;
76
- this.generators.push(new Generator(generatorTypes.endloopAddrsOffset, fine));
75
+ this.addGenerators(new Generator(generatorTypes.endloopAddrsOffset, fine));
77
76
  // coarse generator uses 32768 samples per step
78
77
  const coarse = Math.trunc(diffEnd / 32768);
79
78
  if (coarse !== 0)
80
79
  {
81
- this.generators.push(new Generator(generatorTypes.endloopAddrsCoarseOffset, coarse));
80
+ this.addGenerators(new Generator(generatorTypes.endloopAddrsCoarseOffset, coarse));
82
81
  }
83
82
  }
84
83
  }
85
84
  // correct the key if needed
86
85
  if (sampleKey !== sample.samplePitch)
87
86
  {
88
- this.generators.push(new Generator(generatorTypes.overridingRootKey, sampleKey));
87
+ this.addGenerators(new Generator(generatorTypes.overridingRootKey, sampleKey));
89
88
  }
90
89
  // add sample ID
91
- this.generators.push(new Generator(generatorTypes.sampleID, sampleID));
92
- this.sample = sample;
93
- sample.useCount++;
90
+ this.setSample(sample);
94
91
  }
95
92
  }
@@ -4,8 +4,9 @@ import { DLS_1_NO_VIBRATO_MOD, DLS_1_NO_VIBRATO_PRESSURE, DLSSources } from "./d
4
4
  import { getSF2ModulatorFromArticulator } from "./articulator_converter.js";
5
5
  import { SpessaSynthInfo, SpessaSynthWarn } from "../../utils/loggin.js";
6
6
  import { consoleColors } from "../../utils/other.js";
7
- import { Generator, generatorTypes } from "../basic_soundfont/generator.js";
7
+ import { Generator } from "../basic_soundfont/generator.js";
8
8
  import { Modulator } from "../basic_soundfont/modulator.js";
9
+ import { generatorTypes } from "../basic_soundfont/generator_types.js";
9
10
 
10
11
 
11
12
  /**
@@ -3,11 +3,10 @@ import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
3
3
  import { DLSPreset } from "./dls_preset.js";
4
4
  import { findRIFFListType, readRIFFChunk } from "../basic_soundfont/riff_chunk.js";
5
5
  import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd } from "../../utils/loggin.js";
6
- import { BasicInstrumentZone } from "../basic_soundfont/basic_zones.js";
7
6
  import { consoleColors } from "../../utils/other.js";
8
- import { generatorLimits, generatorTypes } from "../basic_soundfont/generator.js";
9
7
  import { Modulator } from "../basic_soundfont/modulator.js";
10
8
  import { DEFAULT_DLS_CHORUS, DEFAULT_DLS_REVERB } from "./dls_sources.js";
9
+ import { generatorLimits, generatorTypes } from "../basic_soundfont/generator_types.js";
11
10
 
12
11
  /**
13
12
  * @this {DLSSoundFont}
@@ -70,8 +69,7 @@ export function readDLSInstrument(chunk)
70
69
  }
71
70
 
72
71
  // global articulation: essentially global zone
73
- const globalZone = new BasicInstrumentZone();
74
- globalZone.isGlobal = true;
72
+ const globalZone = preset.DLSInstrument.globalZone;
75
73
 
76
74
  // read articulators
77
75
  const globalLart = findRIFFListType(chunks, "lart");
@@ -86,14 +84,13 @@ export function readDLSInstrument(chunk)
86
84
  // reverb
87
85
  if (globalZone.modulators.find(m => m.modulatorDestination === generatorTypes.reverbEffectsSend) === undefined)
88
86
  {
89
- globalZone.modulators.push(Modulator.copy(DEFAULT_DLS_REVERB));
87
+ globalZone.addModulators(Modulator.copy(DEFAULT_DLS_REVERB));
90
88
  }
91
89
  // chorus
92
90
  if (globalZone.modulators.find(m => m.modulatorDestination === generatorTypes.chorusEffectsSend) === undefined)
93
91
  {
94
- globalZone.modulators.push(Modulator.copy(DEFAULT_DLS_CHORUS));
92
+ globalZone.addModulators(Modulator.copy(DEFAULT_DLS_CHORUS));
95
93
  }
96
- preset.DLSInstrument.instrumentZones.push(globalZone);
97
94
 
98
95
  // read regions
99
96
  for (let i = 0; i < regions; i++)
@@ -111,11 +108,11 @@ export function readDLSInstrument(chunk)
111
108
  const zone = this.readRegion(chunk);
112
109
  if (zone)
113
110
  {
114
- preset.DLSInstrument.instrumentZones.push(zone);
111
+ preset.DLSInstrument.addZones(zone);
115
112
  }
116
113
  }
117
114
 
118
- this.presets.push(preset);
119
- this.instruments.push(preset.DLSInstrument);
115
+ this.addPresets(preset);
116
+ this.addInstruments(preset.DLSInstrument);
120
117
  SpessaSynthGroupEnd();
121
118
  }
@@ -4,7 +4,7 @@ import { readArticulation } from "./read_articulation.js";
4
4
  /**
5
5
  * @param lartChunk {RiffChunk|undefined}
6
6
  * @param lar2Chunk {RiffChunk|undefined}
7
- * @param zone {BasicInstrumentZone}
7
+ * @param zone {BasicZone}
8
8
  * @this {DLSSoundFont}
9
9
  */
10
10
  export function readLart(lartChunk, lar2Chunk, zone)
@@ -16,8 +16,8 @@ export function readLart(lartChunk, lar2Chunk, zone)
16
16
  const art1 = readRIFFChunk(lartChunk.chunkData);
17
17
  this.verifyHeader(art1, "art1", "art2");
18
18
  const modsAndGens = readArticulation(art1, true);
19
- zone.generators.push(...modsAndGens.generators);
20
- zone.modulators.push(...modsAndGens.modulators);
19
+ zone.addGenerators(...modsAndGens.generators);
20
+ zone.addModulators(...modsAndGens.modulators);
21
21
  }
22
22
  }
23
23
 
@@ -28,8 +28,8 @@ export function readLart(lartChunk, lar2Chunk, zone)
28
28
  const art2 = readRIFFChunk(lar2Chunk.chunkData);
29
29
  this.verifyHeader(art2, "art2", "art1");
30
30
  const modsAndGens = readArticulation(art2, false);
31
- zone.generators.push(...modsAndGens.generators);
32
- zone.modulators.push(...modsAndGens.modulators);
31
+ zone.addGenerators(...modsAndGens.generators);
32
+ zone.addModulators(...modsAndGens.modulators);
33
33
  }
34
34
  }
35
35
  }
@@ -1,7 +1,8 @@
1
1
  import { readLittleEndian, signedInt16 } from "../../utils/byte_functions/little_endian.js";
2
2
  import { findRIFFListType, readRIFFChunk } from "../basic_soundfont/riff_chunk.js";
3
3
  import { DLSZone } from "./dls_zone.js";
4
- import { Generator, generatorTypes } from "../basic_soundfont/generator.js";
4
+ import { Generator } from "../basic_soundfont/generator.js";
5
+ import { generatorTypes } from "../basic_soundfont/generator_types.js";
5
6
 
6
7
  /**
7
8
  * @this {DLSSoundFont}
@@ -51,7 +52,7 @@ export function readRegion(chunk)
51
52
  const exclusive = readLittleEndian(regionHeader.chunkData, 2);
52
53
  if (exclusive !== 0)
53
54
  {
54
- zone.generators.push(new Generator(generatorTypes.exclusiveClass, exclusive));
55
+ zone.addGenerators(new Generator(generatorTypes.exclusiveClass, exclusive));
55
56
  }
56
57
 
57
58
  // lart
@@ -60,7 +61,6 @@ export function readRegion(chunk)
60
61
  this.readLart(lart, lar2, zone);
61
62
 
62
63
  // wsmp: wave sample chunk
63
- zone.isGlobal = false;
64
64
  const waveSampleChunk = regionChunks.find(c => c.header === "wsmp");
65
65
  // cbSize
66
66
  readLittleEndian(waveSampleChunk.chunkData, 4);
@@ -33,7 +33,16 @@ export class Instrument extends BasicInstrument
33
33
  this.instrumentZonesAmount = amount;
34
34
  for (let i = this.instrumentZoneIndex; i < this.instrumentZonesAmount + this.instrumentZoneIndex; i++)
35
35
  {
36
- this.instrumentZones.push(zones[i]);
36
+ const zone = zones[i];
37
+ if (zone.hasSample())
38
+ {
39
+ this.addZones(zone);
40
+ }
41
+ else
42
+ {
43
+ // global!
44
+ this.globalZone.copyFrom(zone);
45
+ }
37
46
  }
38
47
  }
39
48
  }
@@ -1,24 +1,5 @@
1
1
  import { readLittleEndian, signedInt16 } from "../../utils/byte_functions/little_endian.js";
2
- import { IndexedByteArray } from "../../utils/indexed_array.js";
3
- import { Modulator } from "../basic_soundfont/modulator.js";
4
-
5
-
6
- export class ReadModulator extends Modulator
7
- {
8
- /**
9
- * Creates a modulator
10
- * @param dataArray {IndexedByteArray}
11
- */
12
- constructor(dataArray)
13
- {
14
- const srcEnum = readLittleEndian(dataArray, 2);
15
- const destination = readLittleEndian(dataArray, 2);
16
- const amount = signedInt16(dataArray[dataArray.currentIndex++], dataArray[dataArray.currentIndex++]);
17
- const secSrcEnum = readLittleEndian(dataArray, 2);
18
- const transformType = readLittleEndian(dataArray, 2);
19
- super(srcEnum, secSrcEnum, destination, amount, transformType);
20
- }
21
- }
2
+ import { DecodedModulator, Modulator } from "../basic_soundfont/modulator.js";
22
3
 
23
4
  /**
24
5
  * Reads the modulator read
@@ -27,10 +8,16 @@ export class ReadModulator extends Modulator
27
8
  */
28
9
  export function readModulators(modulatorChunk)
29
10
  {
30
- let gens = [];
11
+ let mods = [];
31
12
  while (modulatorChunk.chunkData.length > modulatorChunk.chunkData.currentIndex)
32
13
  {
33
- gens.push(new ReadModulator(modulatorChunk.chunkData));
14
+ const dataArray = modulatorChunk.chunkData;
15
+ const sourceEnum = readLittleEndian(dataArray, 2);
16
+ const destination = readLittleEndian(dataArray, 2);
17
+ const amount = signedInt16(dataArray[dataArray.currentIndex++], dataArray[dataArray.currentIndex++]);
18
+ const secondarySourceEnum = readLittleEndian(dataArray, 2);
19
+ const transformType = readLittleEndian(dataArray, 2);
20
+ mods.push(new DecodedModulator(sourceEnum, secondarySourceEnum, destination, amount, transformType));
34
21
  }
35
- return gens;
22
+ return mods;
36
23
  }
@@ -43,7 +43,16 @@ export class Preset extends BasicPreset
43
43
  this.presetZonesAmount = amount;
44
44
  for (let i = this.presetZoneStartIndex; i < this.presetZonesAmount + this.presetZoneStartIndex; i++)
45
45
  {
46
- this.presetZones.push(zones[i]);
46
+ const zone = zones[i];
47
+ if (zone.hasInstrument())
48
+ {
49
+ this.presetZones.push(zone);
50
+ }
51
+ else
52
+ {
53
+ // global!
54
+ this.globalZone.copyFrom(zone);
55
+ }
47
56
  }
48
57
  }
49
58
  }
@@ -11,7 +11,7 @@ import { consoleColors } from "../../utils/other.js";
11
11
  import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from "../../utils/loggin.js";
12
12
  import { readBytesAsString } from "../../utils/byte_functions/string.js";
13
13
  import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js";
14
- import { BasicSoundBank } from "../basic_soundfont/basic_soundfont.js";
14
+ import { BasicSoundBank } from "../basic_soundfont/basic_soundbank.js";
15
15
  import { Generator } from "../basic_soundfont/generator.js";
16
16
  import { Modulator } from "../basic_soundfont/modulator.js";
17
17
 
@@ -215,7 +215,6 @@ export class SoundFont2 extends BasicSoundBank
215
215
  * @type {Modulator[]}
216
216
  */
217
217
  let instrumentModulators = readModulators(presetInstrumentModulatorsChunk);
218
-
219
218
  /**
220
219
  * read all the instrument zones
221
220
  * @type {InstrumentZone[]}
@@ -243,9 +242,8 @@ export class SoundFont2 extends BasicSoundBank
243
242
 
244
243
  let presetZones = readPresetZones(presetZonesChunk, presetGenerators, presetModulators, this.instruments);
245
244
 
246
- this.presets.push(...readPresets(presetHeadersChunk, presetZones, this));
247
- this.presets.sort((a, b) => (a.program - b.program) + (a.bank - b.bank));
248
- this._parseInternal();
245
+ this.addPresets(...readPresets(presetHeadersChunk, presetZones, this));
246
+ this.flush();
249
247
  SpessaSynthInfo(
250
248
  `%cParsing finished! %c"${this.soundFontInfo["INAM"]}"%c has %c${this.presets.length} %cpresets,
251
249
  %c${this.instruments.length}%c instruments and %c${this.samples.length}%c samples.`,
@@ -1,9 +1,11 @@
1
1
  import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
2
2
  import { IndexedByteArray } from "../../utils/indexed_array.js";
3
3
  import { RiffChunk } from "../basic_soundfont/riff_chunk.js";
4
- import { BasicInstrumentZone, BasicPresetZone } from "../basic_soundfont/basic_zones.js";
5
- import { Generator, generatorTypes } from "../basic_soundfont/generator.js";
4
+ import { BasicPresetZone } from "../basic_soundfont/basic_preset_zone.js";
5
+ import { Generator } from "../basic_soundfont/generator.js";
6
6
  import { Modulator } from "../basic_soundfont/modulator.js";
7
+ import { generatorTypes } from "../basic_soundfont/generator_types.js";
8
+ import { BasicInstrumentZone } from "../basic_soundfont/basic_instrument_zone.js";
7
9
 
8
10
  /**
9
11
  * zones.js
@@ -23,7 +25,6 @@ export class InstrumentZone extends BasicInstrumentZone
23
25
  this.modulatorZoneStartIndex = readLittleEndian(dataArray, 2);
24
26
  this.modulatorZoneSize = 0;
25
27
  this.generatorZoneSize = 0;
26
- this.isGlobal = true;
27
28
  }
28
29
 
29
30
  setZoneSize(modulatorZoneSize, generatorZoneSize)
@@ -40,7 +41,12 @@ export class InstrumentZone extends BasicInstrumentZone
40
41
  {
41
42
  for (let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
42
43
  {
43
- this.generators.push(generators[i]);
44
+ const g = generators[i];
45
+ if (!g)
46
+ {
47
+ throw new Error("Missing generator in instrument zone! The file may corrupted.");
48
+ }
49
+ this.addGenerators(g);
44
50
  }
45
51
  }
46
52
 
@@ -52,7 +58,12 @@ export class InstrumentZone extends BasicInstrumentZone
52
58
  {
53
59
  for (let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
54
60
  {
55
- this.modulators.push(modulators[i]);
61
+ const m = modulators[i];
62
+ if (!m)
63
+ {
64
+ throw new Error("Missing modulator in instrument zone! The file may corrupted.");
65
+ }
66
+ this.addModulators(m);
56
67
  }
57
68
  }
58
69
 
@@ -65,35 +76,7 @@ export class InstrumentZone extends BasicInstrumentZone
65
76
  let sampleID = this.generators.find(g => g.generatorType === generatorTypes.sampleID);
66
77
  if (sampleID)
67
78
  {
68
- this.sample = samples[sampleID.generatorValue];
69
- this.isGlobal = false;
70
- this.sample.useCount++;
71
- }
72
- }
73
-
74
- /**
75
- * Reads the keyRange of the zone
76
- */
77
- getKeyRange()
78
- {
79
- let range = this.generators.find(g => g.generatorType === generatorTypes.keyRange);
80
- if (range)
81
- {
82
- this.keyRange.min = range.generatorValue & 0x7F;
83
- this.keyRange.max = (range.generatorValue >> 8) & 0x7F;
84
- }
85
- }
86
-
87
- /**
88
- * reads the velolicty range of the zone
89
- */
90
- getVelRange()
91
- {
92
- let range = this.generators.find(g => g.generatorType === generatorTypes.velRange);
93
- if (range)
94
- {
95
- this.velRange.min = range.generatorValue & 0x7F;
96
- this.velRange.max = (range.generatorValue >> 8) & 0x7F;
79
+ this.setSample(samples[sampleID.generatorValue]);
97
80
  }
98
81
  }
99
82
  }
@@ -123,8 +106,6 @@ export function readInstrumentZones(zonesChunk, instrumentGenerators, instrument
123
106
  zones[zones.length - 1].getGenerators(instrumentGenerators);
124
107
  zones[zones.length - 1].getModulators(instrumentModulators);
125
108
  zones[zones.length - 1].getSample(instrumentSamples);
126
- zones[zones.length - 1].getKeyRange();
127
- zones[zones.length - 1].getVelRange();
128
109
  }
129
110
  zones.push(zone);
130
111
  }
@@ -149,7 +130,6 @@ export class PresetZone extends BasicPresetZone
149
130
  this.modulatorZoneStartIndex = readLittleEndian(dataArray, 2);
150
131
  this.modulatorZoneSize = 0;
151
132
  this.generatorZoneSize = 0;
152
- this.isGlobal = true;
153
133
  }
154
134
 
155
135
  setZoneSize(modulatorZoneSize, generatorZoneSize)
@@ -166,7 +146,12 @@ export class PresetZone extends BasicPresetZone
166
146
  {
167
147
  for (let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
168
148
  {
169
- this.generators.push(generators[i]);
149
+ const g = generators[i];
150
+ if (!g)
151
+ {
152
+ throw new Error("Missing generator in preset zone! The file may corrupted.");
153
+ }
154
+ this.addGenerators(g);
170
155
  }
171
156
  }
172
157
 
@@ -178,7 +163,12 @@ export class PresetZone extends BasicPresetZone
178
163
  {
179
164
  for (let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
180
165
  {
181
- this.modulators.push(modulators[i]);
166
+ const m = modulators[i];
167
+ if (!m)
168
+ {
169
+ throw new Error("Missing modulator in preset zone! The file may corrupted.");
170
+ }
171
+ this.addModulators(m);
182
172
  }
183
173
  }
184
174
 
@@ -191,35 +181,7 @@ export class PresetZone extends BasicPresetZone
191
181
  let instrumentID = this.generators.find(g => g.generatorType === generatorTypes.instrument);
192
182
  if (instrumentID)
193
183
  {
194
- this.instrument = instruments[instrumentID.generatorValue];
195
- this.instrument.addUseCount();
196
- this.isGlobal = false;
197
- }
198
- }
199
-
200
- /**
201
- * Reads the keyRange of the zone
202
- */
203
- getKeyRange()
204
- {
205
- let range = this.generators.find(g => g.generatorType === generatorTypes.keyRange);
206
- if (range)
207
- {
208
- this.keyRange.min = range.generatorValue & 0x7F;
209
- this.keyRange.max = (range.generatorValue >> 8) & 0x7F;
210
- }
211
- }
212
-
213
- /**
214
- * reads the velolicty range of the zone
215
- */
216
- getVelRange()
217
- {
218
- let range = this.generators.find(g => g.generatorType === generatorTypes.velRange);
219
- if (range)
220
- {
221
- this.velRange.min = range.generatorValue & 0x7F;
222
- this.velRange.max = (range.generatorValue >> 8) & 0x7F;
184
+ this.setInstrument(instruments[instrumentID.generatorValue]);
223
185
  }
224
186
  }
225
187
  }
@@ -249,8 +211,6 @@ export function readPresetZones(zonesChunk, presetGenerators, presetModulators,
249
211
  zones[zones.length - 1].getGenerators(presetGenerators);
250
212
  zones[zones.length - 1].getModulators(presetModulators);
251
213
  zones[zones.length - 1].getInstrument(instruments);
252
- zones[zones.length - 1].getKeyRange();
253
- zones[zones.length - 1].getVelRange();
254
214
  }
255
215
  zones.push(zone);
256
216
  }
@@ -1,7 +1,7 @@
1
- ## This is the main synthesizer folder.
1
+ ## This is the synthesizer folder.
2
2
 
3
3
  The code here is responsible for making the actual sound.
4
4
  This is the heart of the SpessaSynth library.
5
5
 
6
- - `audio_engine` - the core synthesis engine, it theoretically can run on non-browser environments.
7
- - `audio_effects` - the WebAudioAPI audio effects.
6
+ - `audio_engine` - the core synthesis engine, it theoretically can run on non-browser environments
7
+ - `synth_constants.js` - contains the synthesizer's configuration constants
@@ -6,4 +6,4 @@ The code here is responsible for a single midi channel, synthesizing the sound t
6
6
  - `engine_components` contains the various digital signal processing functions such as the wavetable oscillator, low
7
7
  pass filter, etc.
8
8
 
9
- For those interested, `render_voice.js` file contains the actual DSP synthesis code.
9
+ For those interested, `engine_methods/render_voice.js` file contains the actual DSP synthesis code.
@@ -1,10 +1,9 @@
1
1
  import { getModulatorCurveValue, MOD_PRECOMPUTED_LENGTH } from "./modulator_curves.js";
2
2
  import { VolumeEnvelope } from "./volume_envelope.js";
3
3
  import { ModulationEnvelope } from "./modulation_envelope.js";
4
- import { generatorLimits, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
5
4
  import { Modulator, modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
6
5
  import { NON_CC_INDEX_OFFSET } from "./controller_tables.js";
7
- import { SpessaSynthWarn } from "../../../utils/loggin.js";
6
+ import { generatorLimits, generatorTypes } from "../../../soundfont/basic_soundfont/generator_types.js";
8
7
 
9
8
  /**
10
9
  * compute_modulator.js
@@ -146,22 +145,23 @@ export function computeModulators(voice, sourceUsesCC = -1, sourceIndex = 0)
146
145
  modulatedGenerators.set(generators);
147
146
  modulators.forEach(mod =>
148
147
  {
149
- const limits = generatorLimits[mod.modulatorDestination];
150
- if (!limits)
151
- {
152
- SpessaSynthWarn(`Invalid modulator: ${mod.modulatorDestination}`);
153
- return;
154
- }
155
- const newValue = modulatedGenerators[mod.modulatorDestination] + computeModulator(
148
+ modulatedGenerators[mod.modulatorDestination] += computeModulator(
156
149
  this.midiControllers,
157
150
  mod,
158
151
  voice
159
152
  );
160
- modulatedGenerators[mod.modulatorDestination] = Math.max(
161
- limits.min,
162
- Math.min(newValue, limits.max)
163
- );
164
153
  });
154
+ // apply limits
155
+ for (let gen = 0; gen < modulatedGenerators.length; gen++)
156
+ {
157
+ const limit = generatorLimits[gen];
158
+ if (!limit)
159
+ {
160
+ // skip unused
161
+ continue;
162
+ }
163
+ modulatedGenerators[gen] = Math.min(limit.max, Math.max(limit.min, modulatedGenerators[gen]));
164
+ }
165
165
  VolumeEnvelope.recalculate(voice);
166
166
  ModulationEnvelope.recalculate(voice);
167
167
  return;
@@ -201,14 +201,15 @@ export function computeModulators(voice, sourceUsesCC = -1, sourceIndex = 0)
201
201
  {
202
202
  if (m.modulatorDestination === destination)
203
203
  {
204
- const limits = generatorLimits[mod.modulatorDestination];
205
- const newValue = modulatedGenerators[mod.modulatorDestination] + m.currentValue;
206
- modulatedGenerators[mod.modulatorDestination] = Math.max(
207
- limits.min,
208
- Math.min(newValue, limits.max)
209
- );
204
+ modulatedGenerators[destination] += m.currentValue;
210
205
  }
211
206
  });
207
+ // apply limits
208
+ const limits = generatorLimits[destination];
209
+ modulatedGenerators[destination] = Math.max(
210
+ limits.min,
211
+ Math.min(modulatedGenerators[destination], limits.max)
212
+ );
212
213
  computedDestinations.add(destination);
213
214
  }
214
215
  }