spessasynth_core 3.27.8 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +85 -51
  2. package/dist/index.d.ts +4057 -0
  3. package/dist/index.js +17188 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +23 -6
  6. package/index.js +0 -132
  7. package/src/externals/README.md +0 -6
  8. package/src/externals/fflate/LICENSE +0 -21
  9. package/src/externals/fflate/fflate.min.js +0 -1
  10. package/src/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  11. package/src/externals/stbvorbis_sync/LICENSE +0 -202
  12. package/src/externals/stbvorbis_sync/NOTICE +0 -6
  13. package/src/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  14. package/src/midi/README.md +0 -32
  15. package/src/midi/basic_midi.js +0 -587
  16. package/src/midi/midi_builder.js +0 -203
  17. package/src/midi/midi_loader.js +0 -321
  18. package/src/midi/midi_message.js +0 -254
  19. package/src/midi/midi_sequence.js +0 -230
  20. package/src/midi/midi_tools/get_note_times.js +0 -154
  21. package/src/midi/midi_tools/midi_editor.js +0 -611
  22. package/src/midi/midi_tools/midi_writer.js +0 -105
  23. package/src/midi/midi_tools/rmidi_writer.js +0 -566
  24. package/src/midi/midi_tools/used_keys_loaded.js +0 -256
  25. package/src/midi/xmf_loader.js +0 -454
  26. package/src/sequencer/README.md +0 -9
  27. package/src/sequencer/events.js +0 -81
  28. package/src/sequencer/play.js +0 -362
  29. package/src/sequencer/process_event.js +0 -165
  30. package/src/sequencer/process_tick.js +0 -104
  31. package/src/sequencer/sequencer_engine.js +0 -372
  32. package/src/sequencer/song_control.js +0 -196
  33. package/src/soundfont/README.md +0 -11
  34. package/src/soundfont/basic_soundfont/basic_global_zone.js +0 -6
  35. package/src/soundfont/basic_soundfont/basic_instrument.js +0 -115
  36. package/src/soundfont/basic_soundfont/basic_instrument_zone.js +0 -45
  37. package/src/soundfont/basic_soundfont/basic_preset.js +0 -313
  38. package/src/soundfont/basic_soundfont/basic_preset_zone.js +0 -39
  39. package/src/soundfont/basic_soundfont/basic_sample.js +0 -477
  40. package/src/soundfont/basic_soundfont/basic_soundbank.js +0 -740
  41. package/src/soundfont/basic_soundfont/basic_zone.js +0 -145
  42. package/src/soundfont/basic_soundfont/generator.js +0 -76
  43. package/src/soundfont/basic_soundfont/generator_types.js +0 -151
  44. package/src/soundfont/basic_soundfont/modulator.js +0 -581
  45. package/src/soundfont/basic_soundfont/riff_chunk.js +0 -195
  46. package/src/soundfont/basic_soundfont/write_dls/art2.js +0 -174
  47. package/src/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  48. package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -374
  49. package/src/soundfont/basic_soundfont/write_dls/ins.js +0 -85
  50. package/src/soundfont/basic_soundfont/write_dls/lins.js +0 -15
  51. package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  52. package/src/soundfont/basic_soundfont/write_dls/rgn2.js +0 -120
  53. package/src/soundfont/basic_soundfont/write_dls/wave.js +0 -71
  54. package/src/soundfont/basic_soundfont/write_dls/write_dls.js +0 -124
  55. package/src/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  56. package/src/soundfont/basic_soundfont/write_dls/wvpl.js +0 -35
  57. package/src/soundfont/basic_soundfont/write_sf2/ibag.js +0 -60
  58. package/src/soundfont/basic_soundfont/write_sf2/igen.js +0 -91
  59. package/src/soundfont/basic_soundfont/write_sf2/imod.js +0 -62
  60. package/src/soundfont/basic_soundfont/write_sf2/inst.js +0 -42
  61. package/src/soundfont/basic_soundfont/write_sf2/pbag.js +0 -57
  62. package/src/soundfont/basic_soundfont/write_sf2/pgen.js +0 -92
  63. package/src/soundfont/basic_soundfont/write_sf2/phdr.js +0 -61
  64. package/src/soundfont/basic_soundfont/write_sf2/pmod.js +0 -62
  65. package/src/soundfont/basic_soundfont/write_sf2/sdta.js +0 -131
  66. package/src/soundfont/basic_soundfont/write_sf2/shdr.js +0 -77
  67. package/src/soundfont/basic_soundfont/write_sf2/write.js +0 -287
  68. package/src/soundfont/dls/articulator_converter.js +0 -402
  69. package/src/soundfont/dls/dls_destinations.js +0 -38
  70. package/src/soundfont/dls/dls_instrument.js +0 -20
  71. package/src/soundfont/dls/dls_preset.js +0 -43
  72. package/src/soundfont/dls/dls_sample.js +0 -238
  73. package/src/soundfont/dls/dls_soundfont.js +0 -183
  74. package/src/soundfont/dls/dls_sources.js +0 -63
  75. package/src/soundfont/dls/dls_zone.js +0 -89
  76. package/src/soundfont/dls/read_articulation.js +0 -300
  77. package/src/soundfont/dls/read_instrument.js +0 -118
  78. package/src/soundfont/dls/read_instrument_list.js +0 -17
  79. package/src/soundfont/dls/read_lart.js +0 -35
  80. package/src/soundfont/dls/read_region.js +0 -157
  81. package/src/soundfont/dls/read_samples.js +0 -154
  82. package/src/soundfont/load_soundfont.js +0 -21
  83. package/src/soundfont/read_sf2/generators.js +0 -43
  84. package/src/soundfont/read_sf2/instrument_zones.js +0 -75
  85. package/src/soundfont/read_sf2/instruments.js +0 -71
  86. package/src/soundfont/read_sf2/modulators.js +0 -25
  87. package/src/soundfont/read_sf2/preset_zones.js +0 -79
  88. package/src/soundfont/read_sf2/presets.js +0 -80
  89. package/src/soundfont/read_sf2/samples.js +0 -317
  90. package/src/soundfont/read_sf2/soundfont.js +0 -452
  91. package/src/soundfont/read_sf2/zones.js +0 -28
  92. package/src/synthetizer/README.md +0 -7
  93. package/src/synthetizer/audio_engine/README.md +0 -9
  94. package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -289
  95. package/src/synthetizer/audio_engine/engine_components/controller_tables.js +0 -90
  96. package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +0 -95
  97. package/src/synthetizer/audio_engine/engine_components/enums.js +0 -18
  98. package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -151
  99. package/src/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  100. package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  101. package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -551
  102. package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  103. package/src/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  104. package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -265
  105. package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -124
  106. package/src/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  107. package/src/synthetizer/audio_engine/engine_components/voice.js +0 -525
  108. package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -402
  109. package/src/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -274
  110. package/src/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -159
  111. package/src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -53
  112. package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -254
  113. package/src/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -20
  114. package/src/synthetizer/audio_engine/engine_methods/data_entry/awe32.js +0 -198
  115. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -281
  116. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -109
  117. package/src/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  118. package/src/synthetizer/audio_engine/engine_methods/note_on.js +0 -220
  119. package/src/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  120. package/src/synthetizer/audio_engine/engine_methods/program_change.js +0 -35
  121. package/src/synthetizer/audio_engine/engine_methods/render_voice.js +0 -214
  122. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/embedded_sound_bank.js +0 -42
  123. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -0
  124. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/update_preset_list.js +0 -19
  125. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -23
  126. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -56
  127. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  128. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  129. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  130. package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -1058
  131. package/src/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -23
  132. package/src/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -31
  133. package/src/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -29
  134. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  135. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -26
  136. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  137. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  138. package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  139. package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  140. package/src/synthetizer/audio_engine/main_processor.js +0 -817
  141. package/src/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -16
  142. package/src/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  143. package/src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -116
  144. package/src/synthetizer/audio_engine/synth_processor_options.js +0 -18
  145. package/src/synthetizer/synth_constants.js +0 -26
  146. package/src/utils/README.md +0 -8
  147. package/src/utils/buffer_to_wav.js +0 -197
  148. package/src/utils/byte_functions/big_endian.js +0 -32
  149. package/src/utils/byte_functions/little_endian.js +0 -77
  150. package/src/utils/byte_functions/string.js +0 -92
  151. package/src/utils/byte_functions/variable_length_quantity.js +0 -42
  152. package/src/utils/fill_with_defaults.js +0 -21
  153. package/src/utils/indexed_array.js +0 -34
  154. package/src/utils/loggin.js +0 -71
  155. package/src/utils/other.js +0 -92
  156. package/src/utils/sysex_detector.js +0 -58
  157. package/src/utils/xg_hacks.js +0 -193
@@ -1,131 +0,0 @@
1
- import { IndexedByteArray } from "../../../utils/indexed_array.js";
2
- import { writeStringAsBytes } from "../../../utils/byte_functions/string.js";
3
- import { writeLittleEndian } from "../../../utils/byte_functions/little_endian.js";
4
- import { SpessaSynthInfo } from "../../../utils/loggin.js";
5
- import { consoleColors } from "../../../utils/other.js";
6
-
7
- /*
8
- Sdta structure:
9
-
10
- LIST chunk
11
- - "sdta" ASCII string
12
- - smpl chunk
13
- - - raw data
14
- */
15
-
16
- // in bytes, from the start of sdta-LIST to the first actual sample
17
- const SDTA_TO_DATA_OFFSET =
18
- 4 + // "LIST"
19
- 4 + // sdta size
20
- 4 + // "sdta"
21
- 4 + // "smpl"
22
- 4; // smpl size
23
-
24
- /**
25
- * @this {BasicSoundBank}
26
- * @param smplStartOffsets {number[]}
27
- * @param smplEndOffsets {number[]}
28
- * @param compress {boolean}
29
- * @param decompress {boolean}
30
- * @param vorbisFunc {SampleEncodingFunction}
31
- * @param progressFunc {ProgressFunction|undefined}
32
- * @returns {Uint8Array}
33
- */
34
- export async function getSDTA(smplStartOffsets,
35
- smplEndOffsets,
36
- compress,
37
- decompress,
38
- vorbisFunc,
39
- progressFunc
40
- )
41
- {
42
- // write smpl: write int16 data of each sample linearly
43
- // get size (calling getAudioData twice doesn't matter since it gets cached)
44
- let writtenCount = 0;
45
- let smplChunkSize = 0;
46
- const sampleDatas = [];
47
-
48
- // linear async is faster here as the writing function usually uses a single wasm instance
49
- for (const s of this.samples)
50
- {
51
- if (compress)
52
- {
53
- await s.compressSample(vorbisFunc);
54
- }
55
- if (decompress)
56
- {
57
- s.setAudioData(s.getAudioData());
58
- }
59
-
60
- // raw data: either copy s16le or encoded vorbis or encode manually if overridden
61
- // use set timeout so the thread doesn't die
62
- const r = s.getRawData(true);
63
- writtenCount++;
64
- progressFunc?.(s.sampleName, writtenCount, this.samples.length);
65
-
66
- SpessaSynthInfo(
67
- `%cEncoded sample %c${writtenCount}. ${s.sampleName}%c of %c${this.samples.length}%c. Compressed: %c${s.isCompressed}%c.`,
68
- consoleColors.info,
69
- consoleColors.recognized,
70
- consoleColors.info,
71
- consoleColors.recognized,
72
- consoleColors.info,
73
- s.isCompressed ? consoleColors.recognized : consoleColors.unrecognized,
74
- consoleColors.info
75
- );
76
-
77
- /* 6.1 Sample Data Format in the smpl Sub-chunk
78
- Each sample is followed by a minimum of forty-six zero
79
- valued sample data points. These zero valued data points are necessary to guarantee that any reasonable upward pitch shift
80
- using any reasonable interpolator can loop on zero data at the end of the sound.
81
- This doesn't apply to sf3 tho
82
- */
83
- smplChunkSize += r.length + (s.isCompressed ? 0 : 92);
84
- sampleDatas.push(r);
85
- }
86
-
87
- if (smplChunkSize % 2 !== 0)
88
- {
89
- smplChunkSize++;
90
- }
91
-
92
- const sdta = new IndexedByteArray(smplChunkSize + SDTA_TO_DATA_OFFSET);
93
-
94
- // avoid using writeRIFFChunk for performance
95
- // sdta chunk
96
- writeStringAsBytes(sdta, "LIST");
97
- // "sdta" + full smpl length
98
- writeLittleEndian(sdta, smplChunkSize + SDTA_TO_DATA_OFFSET - 8, 4);
99
- writeStringAsBytes(sdta, "sdta");
100
- writeStringAsBytes(sdta, "smpl");
101
- writeLittleEndian(sdta, smplChunkSize, 4);
102
-
103
- let offset = 0;
104
- // write out
105
- this.samples.forEach((sample, i) =>
106
- {
107
- const data = sampleDatas[i];
108
- sdta.set(data, offset + SDTA_TO_DATA_OFFSET);
109
- let startOffset;
110
- let endOffset;
111
- if (sample.isCompressed)
112
- {
113
- // sf3 offset is in bytes
114
- startOffset = offset;
115
- endOffset = startOffset + data.length;
116
- }
117
- else
118
- {
119
- // sf2 in sample data points
120
- startOffset = offset / 2; // inclusive
121
- endOffset = startOffset + data.length / 2; // exclusive
122
- offset += 92; // 46 sample data points
123
- }
124
- offset += data.length;
125
- smplStartOffsets.push(startOffset);
126
-
127
- smplEndOffsets.push(endOffset);
128
- });
129
-
130
- return sdta;
131
- }
@@ -1,77 +0,0 @@
1
- import { IndexedByteArray } from "../../../utils/indexed_array.js";
2
- import { writeStringAsBytes } from "../../../utils/byte_functions/string.js";
3
- import { writeDword, writeWord } from "../../../utils/byte_functions/little_endian.js";
4
- import { writeRIFFChunkRaw } from "../riff_chunk.js";
5
- import { SF3_BIT_FLIT } from "../../read_sf2/samples.js";
6
-
7
- /**
8
- * @this {BasicSoundBank}
9
- * @param smplStartOffsets {number[]}
10
- * @param smplEndOffsets {number[]}
11
- * @returns {ReturnedExtendedSf2Chunks}
12
- */
13
- export function getSHDR(smplStartOffsets, smplEndOffsets)
14
- {
15
- const sampleLength = 46;
16
- const shdrSize = sampleLength * (this.samples.length + 1); // +1 because EOP
17
- const shdrData = new IndexedByteArray(shdrSize);
18
- // https://github.com/spessasus/soundfont-proposals/blob/main/extended_limits.md
19
- const xshdrData = new IndexedByteArray(shdrSize);
20
- let maxSampleLink = 0;
21
- this.samples.forEach((sample, index) =>
22
- {
23
- // sample name
24
- writeStringAsBytes(shdrData, sample.sampleName.substring(0, 20), 20);
25
- writeStringAsBytes(xshdrData, sample.sampleName.substring(20), 20);
26
- // start offset
27
- const dwStart = smplStartOffsets[index];
28
- writeDword(shdrData, dwStart);
29
- xshdrData.currentIndex += 4;
30
- // end offset
31
- const dwEnd = smplEndOffsets[index];
32
- writeDword(shdrData, dwEnd);
33
- xshdrData.currentIndex += 4;
34
- // loop is stored as relative in sample points, change it to absolute sample points here
35
- let loopStart = sample.sampleLoopStartIndex + dwStart;
36
- let loopEnd = sample.sampleLoopEndIndex + dwStart;
37
- if (sample.isCompressed)
38
- {
39
- // https://github.com/FluidSynth/fluidsynth/wiki/SoundFont3Format
40
- loopStart -= dwStart;
41
- loopEnd -= dwStart;
42
- }
43
- writeDword(shdrData, loopStart);
44
- writeDword(shdrData, loopEnd);
45
- // sample rate
46
- writeDword(shdrData, sample.sampleRate);
47
- // pitch and correction
48
- shdrData[shdrData.currentIndex++] = sample.samplePitch;
49
- shdrData[shdrData.currentIndex++] = sample.samplePitchCorrection;
50
- // skip all those for xshdr
51
- xshdrData.currentIndex += 14;
52
- // sample link
53
- const sampleLinkIndex = this.samples.indexOf(sample.linkedSample);
54
- writeWord(shdrData, Math.max(0, sampleLinkIndex) & 0xFFFF);
55
- writeWord(xshdrData, Math.max(0, sampleLinkIndex) >> 16);
56
- maxSampleLink = Math.max(maxSampleLink, sampleLinkIndex);
57
- // sample type: add byte if compressed
58
- let type = sample.sampleType;
59
- if (sample.isCompressed)
60
- {
61
- type |= SF3_BIT_FLIT;
62
- }
63
- writeWord(shdrData, type);
64
- xshdrData.currentIndex += 2;
65
- });
66
-
67
- // write EOS and zero everything else
68
- writeStringAsBytes(shdrData, "EOS", sampleLength);
69
- writeStringAsBytes(xshdrData, "EOS", sampleLength);
70
- const shdr = writeRIFFChunkRaw("shdr", shdrData);
71
- const xshdr = writeRIFFChunkRaw("shdr", xshdrData);
72
- return {
73
- pdta: shdr,
74
- xdta: xshdr,
75
- highestIndex: maxSampleLink
76
- };
77
- }
@@ -1,287 +0,0 @@
1
- import { IndexedByteArray } from "../../../utils/indexed_array.js";
2
- import { writeRIFFChunkParts, writeRIFFChunkRaw } from "../riff_chunk.js";
3
- import { getStringBytes } 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 { writeLittleEndian, writeWord } from "../../../utils/byte_functions/little_endian.js";
16
- import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd, SpessaSynthInfo } from "../../../utils/loggin.js";
17
- import { MOD_BYTE_SIZE } from "../modulator.js";
18
- import { fillWithDefaults } from "../../../utils/fill_with_defaults.js";
19
-
20
- /**
21
- * @typedef {function} ProgressFunction
22
- * @param {string} sampleName - the written sample name.
23
- * @param {number} sampleIndex - the sample's index.
24
- * @param {number} sampleCount - the total sample count for progress displaying.
25
- */
26
-
27
- /**
28
- * @typedef {Object} SoundFont2WriteOptions
29
- * @property {boolean} compress - if the soundfont should be compressed with a given function.
30
- * @property {SampleEncodingFunction} compressionFunction -
31
- * the encode vorbis function. It can be undefined if not compressed.
32
- * @property {ProgressFunction} progressFunction - a function to show progress for writing large banks. It can be undefined.
33
- * @property {boolean} writeDefaultModulators - if the DMOD chunk should be written.
34
- * Recommended.
35
- * @property {boolean} writeExtendedLimits - if the xdta chunk should be written to allow virtually infinite parameters.
36
- * Recommended.
37
- * @property {boolean} decompress - if an sf3 bank should be decompressed back to sf2. Not recommended.
38
- */
39
-
40
-
41
- /**
42
- * @typedef {Object} ReturnedExtendedSf2Chunks
43
- * @property {IndexedByteArray} pdta - the pdta part of the chunk
44
- * @property {IndexedByteArray} xdta - the xdta (https://github.com/spessasus/soundfont-proposals/blob/main/extended_limits.md) part of the chunk
45
- * @property {number} highestIndex - the highest index written (0 if not applicable). Used for determining whether the xdta chunk is necessary.
46
- */
47
-
48
- /**
49
- * @type {SoundFont2WriteOptions}
50
- */
51
- const DEFAULT_WRITE_OPTIONS = {
52
- compress: false,
53
- compressionQuality: 0.5,
54
- compressionFunction: undefined,
55
- progressFunction: undefined,
56
- writeDefaultModulators: true,
57
- writeExtendedLimits: true,
58
- decompress: false
59
- };
60
-
61
- /**
62
- * Write the soundfont as an .sf2 file
63
- * @this {BasicSoundBank}
64
- * @param {Partial<SoundFont2WriteOptions>} options
65
- * @returns {Uint8Array}
66
- */
67
- export async function write(options = DEFAULT_WRITE_OPTIONS)
68
- {
69
- options = fillWithDefaults(options, DEFAULT_WRITE_OPTIONS);
70
- if (options?.compress)
71
- {
72
- if (typeof options?.compressionFunction !== "function")
73
- {
74
- throw new Error("No compression function supplied but compression enabled.");
75
- }
76
- if (options?.decompress)
77
- {
78
- throw new Error("Decompressed and compressed at the same time.");
79
- }
80
- }
81
- SpessaSynthGroupCollapsed(
82
- "%cSaving soundfont...",
83
- consoleColors.info
84
- );
85
- SpessaSynthInfo(
86
- `%cCompression: %c${options?.compress || "false"}%c quality: %c${options?.compressionQuality || "none"}`,
87
- consoleColors.info,
88
- consoleColors.recognized,
89
- consoleColors.info,
90
- consoleColors.recognized
91
- );
92
- SpessaSynthInfo(
93
- "%cWriting INFO...",
94
- consoleColors.info
95
- );
96
- /**
97
- * Write INFO
98
- * @type {IndexedByteArray[]}
99
- */
100
- const infoArrays = [];
101
- this.soundFontInfo["ISFT"] = "SpessaSynth"; // ( ͡° ͜ʖ ͡°)
102
- if (options?.compress || this.samples.some(s => s.isCompressed))
103
- {
104
- this.soundFontInfo["ifil"] = "3.0"; // set version to 3
105
- }
106
- if (options?.decompress)
107
- {
108
- this.soundFontInfo["ifil"] = "2.4"; // set version to 2.04
109
- }
110
-
111
- if (options?.writeDefaultModulators)
112
- {
113
- // trigger the DMOD write
114
- this.soundFontInfo["DMOD"] = `${this.defaultModulators.length} Modulators`;
115
- this.customDefaultModulators = true;
116
- }
117
- else
118
- {
119
- delete this.soundFontInfo["DMOD"];
120
- }
121
-
122
- for (const [type, data] of Object.entries(this.soundFontInfo))
123
- {
124
- if (type === "ifil" || type === "iver")
125
- {
126
- const major = parseInt(data.split(".")[0]);
127
- const minor = parseInt(data.split(".")[1]);
128
- const ckdata = new IndexedByteArray(4);
129
- writeWord(ckdata, major);
130
- writeWord(ckdata, minor);
131
- infoArrays.push(writeRIFFChunkRaw(type, ckdata));
132
- }
133
- else if (type === "DMOD")
134
- {
135
- const mods = this.defaultModulators;
136
- SpessaSynthInfo(
137
- `%cWriting %c${mods.length}%c default modulators...`,
138
- consoleColors.info,
139
- consoleColors.recognized,
140
- consoleColors.info
141
- );
142
- let dmodsize = MOD_BYTE_SIZE + mods.length * MOD_BYTE_SIZE;
143
- const dmoddata = new IndexedByteArray(dmodsize);
144
- for (const mod of mods)
145
- {
146
- writeWord(dmoddata, mod.getSourceEnum());
147
- writeWord(dmoddata, mod.modulatorDestination);
148
- writeWord(dmoddata, mod.transformAmount);
149
- writeWord(dmoddata, mod.getSecSrcEnum());
150
- writeWord(dmoddata, mod.transformType);
151
- }
152
-
153
- // terminal modulator, is zero
154
- writeLittleEndian(dmoddata, 0, MOD_BYTE_SIZE);
155
-
156
- infoArrays.push(writeRIFFChunkRaw(type, dmoddata));
157
- }
158
- else
159
- {
160
- infoArrays.push(writeRIFFChunkRaw(
161
- type,
162
- getStringBytes(data, true, true) // pad with zero and ensure even length
163
- ));
164
- }
165
- }
166
-
167
- SpessaSynthInfo(
168
- "%cWriting SDTA...",
169
- consoleColors.info
170
- );
171
- // write sdta
172
- const smplStartOffsets = [];
173
- const smplEndOffsets = [];
174
- const sdtaChunk = await getSDTA.call(
175
- this,
176
- smplStartOffsets,
177
- smplEndOffsets,
178
- options.compress,
179
- options.decompress,
180
- options?.compressionFunction,
181
- options?.progressFunction
182
- );
183
-
184
- SpessaSynthInfo(
185
- "%cWriting PDTA...",
186
- consoleColors.info
187
- );
188
- // write pdta
189
- // go in reverse so the indexes are correct
190
- // instruments
191
- SpessaSynthInfo(
192
- "%cWriting SHDR...",
193
- consoleColors.info
194
- );
195
- const shdrChunk = getSHDR.call(this, smplStartOffsets, smplEndOffsets);
196
- SpessaSynthInfo(
197
- "%cWriting IGEN...",
198
- consoleColors.info
199
- );
200
- const igenChunk = getIGEN.call(this);
201
- SpessaSynthInfo(
202
- "%cWriting IMOD...",
203
- consoleColors.info
204
- );
205
- const imodChunk = getIMOD.call(this);
206
- SpessaSynthInfo(
207
- "%cWriting IBAG...",
208
- consoleColors.info
209
- );
210
- const ibagChunk = getIBAG.call(this);
211
- SpessaSynthInfo(
212
- "%cWriting INST...",
213
- consoleColors.info
214
- );
215
- const instChunk = getINST.call(this);
216
- SpessaSynthInfo(
217
- "%cWriting PGEN...",
218
- consoleColors.info
219
- );
220
- // presets
221
- const pgenChunk = getPGEN.call(this);
222
- SpessaSynthInfo(
223
- "%cWriting PMOD...",
224
- consoleColors.info
225
- );
226
- const pmodChunk = getPMOD.call(this);
227
- SpessaSynthInfo(
228
- "%cWriting PBAG...",
229
- consoleColors.info
230
- );
231
- const pbagChunk = getPBAG.call(this);
232
- SpessaSynthInfo(
233
- "%cWriting PHDR...",
234
- consoleColors.info
235
- );
236
- const phdrChunk = getPHDR.call(this);
237
- /**
238
- * @type {ReturnedExtendedSf2Chunks[]}
239
- */
240
- const chunks = [phdrChunk, pbagChunk, pmodChunk, pgenChunk, instChunk, ibagChunk, imodChunk, igenChunk, shdrChunk];
241
- // combine in the sfspec order
242
- const pdtaChunk = writeRIFFChunkParts(
243
- "pdta",
244
- chunks.map(c => c.pdta),
245
- true
246
- );
247
- const maxIndex = Math.max(
248
- ...chunks.map(c => c.highestIndex)
249
- );
250
-
251
- const writeXdta = options.writeExtendedLimits && (
252
- maxIndex > 0xFFFF
253
- || this.presets.some(p => p.presetName.length > 20)
254
- || this.instruments.some(i => i.instrumentName.length > 20)
255
- || this.samples.some(s => s.sampleName.length > 20)
256
- );
257
-
258
- if (writeXdta)
259
- {
260
- SpessaSynthInfo(
261
- `%cWriting the xdta chunk! Max index: %c${maxIndex}`,
262
- consoleColors.info,
263
- consoleColors.value
264
- );
265
- // https://github.com/spessasus/soundfont-proposals/blob/main/extended_limits.md
266
- const xpdtaChunk = writeRIFFChunkParts("xdta", chunks.map(c => c.xdta), true);
267
- infoArrays.push(xpdtaChunk);
268
- }
269
-
270
- const infoChunk = writeRIFFChunkParts("INFO", infoArrays, true);
271
- SpessaSynthInfo(
272
- "%cWriting the output file...",
273
- consoleColors.info
274
- );
275
- // finally, combine everything
276
- const main = writeRIFFChunkParts(
277
- "RIFF",
278
- [getStringBytes("sfbk"), infoChunk, sdtaChunk, pdtaChunk]
279
- );
280
- SpessaSynthInfo(
281
- `%cSaved succesfully! Final file size: %c${main.length}`,
282
- consoleColors.info,
283
- consoleColors.recognized
284
- );
285
- SpessaSynthGroupEnd();
286
- return main;
287
- }