spessasynth_core 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/LICENSE +3 -26
  2. package/README.md +156 -474
  3. package/index.js +73 -8
  4. package/package.json +21 -8
  5. package/src/externals/fflate/LICENSE +21 -0
  6. package/src/externals/fflate/fflate.min.js +1 -0
  7. package/src/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +12 -0
  8. package/src/externals/stbvorbis_sync/LICENSE +202 -0
  9. package/src/externals/stbvorbis_sync/NOTICE +6 -0
  10. package/src/externals/stbvorbis_sync/stbvorbis_sync.min.js +1 -0
  11. package/src/midi/README.md +32 -0
  12. package/src/midi/basic_midi.js +567 -0
  13. package/src/midi/midi_builder.js +202 -0
  14. package/src/midi/midi_loader.js +324 -0
  15. package/{spessasynth_core/midi_parser → src/midi}/midi_message.js +58 -35
  16. package/src/midi/midi_sequence.js +224 -0
  17. package/src/midi/midi_tools/get_note_times.js +154 -0
  18. package/src/midi/midi_tools/midi_editor.js +611 -0
  19. package/src/midi/midi_tools/midi_writer.js +99 -0
  20. package/src/midi/midi_tools/rmidi_writer.js +567 -0
  21. package/src/midi/midi_tools/used_keys_loaded.js +238 -0
  22. package/src/midi/xmf_loader.js +454 -0
  23. package/src/sequencer/README.md +5 -0
  24. package/src/sequencer/events.js +81 -0
  25. package/src/sequencer/play.js +349 -0
  26. package/src/sequencer/process_event.js +165 -0
  27. package/{spessasynth_core/sequencer/worklet_sequencer → src/sequencer}/process_tick.js +103 -84
  28. package/src/sequencer/sequencer_engine.js +367 -0
  29. package/src/sequencer/song_control.js +201 -0
  30. package/src/soundfont/README.md +13 -0
  31. package/src/soundfont/basic_soundfont/basic_instrument.js +77 -0
  32. package/src/soundfont/basic_soundfont/basic_preset.js +336 -0
  33. package/src/soundfont/basic_soundfont/basic_sample.js +206 -0
  34. package/src/soundfont/basic_soundfont/basic_soundfont.js +565 -0
  35. package/src/soundfont/basic_soundfont/basic_zone.js +64 -0
  36. package/src/soundfont/basic_soundfont/basic_zones.js +43 -0
  37. package/src/soundfont/basic_soundfont/generator.js +220 -0
  38. package/src/soundfont/basic_soundfont/modulator.js +378 -0
  39. package/src/soundfont/basic_soundfont/riff_chunk.js +149 -0
  40. package/src/soundfont/basic_soundfont/write_dls/art2.js +173 -0
  41. package/src/soundfont/basic_soundfont/write_dls/articulator.js +49 -0
  42. package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +400 -0
  43. package/src/soundfont/basic_soundfont/write_dls/ins.js +103 -0
  44. package/src/soundfont/basic_soundfont/write_dls/lins.js +18 -0
  45. package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +330 -0
  46. package/src/soundfont/basic_soundfont/write_dls/rgn2.js +121 -0
  47. package/src/soundfont/basic_soundfont/write_dls/wave.js +94 -0
  48. package/src/soundfont/basic_soundfont/write_dls/write_dls.js +119 -0
  49. package/src/soundfont/basic_soundfont/write_dls/wsmp.js +78 -0
  50. package/src/soundfont/basic_soundfont/write_dls/wvpl.js +32 -0
  51. package/src/soundfont/basic_soundfont/write_sf2/ibag.js +39 -0
  52. package/src/soundfont/basic_soundfont/write_sf2/igen.js +80 -0
  53. package/src/soundfont/basic_soundfont/write_sf2/imod.js +46 -0
  54. package/src/soundfont/basic_soundfont/write_sf2/inst.js +34 -0
  55. package/src/soundfont/basic_soundfont/write_sf2/pbag.js +39 -0
  56. package/src/soundfont/basic_soundfont/write_sf2/pgen.js +82 -0
  57. package/src/soundfont/basic_soundfont/write_sf2/phdr.js +42 -0
  58. package/src/soundfont/basic_soundfont/write_sf2/pmod.js +46 -0
  59. package/src/soundfont/basic_soundfont/write_sf2/sdta.js +80 -0
  60. package/src/soundfont/basic_soundfont/write_sf2/shdr.js +55 -0
  61. package/src/soundfont/basic_soundfont/write_sf2/write.js +222 -0
  62. package/src/soundfont/dls/articulator_converter.js +396 -0
  63. package/src/soundfont/dls/dls_destinations.js +38 -0
  64. package/src/soundfont/dls/dls_preset.js +44 -0
  65. package/src/soundfont/dls/dls_sample.js +75 -0
  66. package/src/soundfont/dls/dls_soundfont.js +186 -0
  67. package/src/soundfont/dls/dls_sources.js +62 -0
  68. package/src/soundfont/dls/dls_zone.js +95 -0
  69. package/src/soundfont/dls/read_articulation.js +299 -0
  70. package/src/soundfont/dls/read_instrument.js +121 -0
  71. package/src/soundfont/dls/read_instrument_list.js +17 -0
  72. package/src/soundfont/dls/read_lart.js +35 -0
  73. package/src/soundfont/dls/read_region.js +152 -0
  74. package/src/soundfont/dls/read_samples.js +270 -0
  75. package/src/soundfont/load_soundfont.js +21 -0
  76. package/src/soundfont/read_sf2/generators.js +46 -0
  77. package/{spessasynth_core/soundfont/chunk → src/soundfont/read_sf2}/instruments.js +20 -14
  78. package/src/soundfont/read_sf2/modulators.js +36 -0
  79. package/src/soundfont/read_sf2/presets.js +80 -0
  80. package/src/soundfont/read_sf2/samples.js +304 -0
  81. package/src/soundfont/read_sf2/soundfont.js +305 -0
  82. package/{spessasynth_core/soundfont/chunk → src/soundfont/read_sf2}/zones.js +68 -69
  83. package/src/synthetizer/README.md +7 -0
  84. package/src/synthetizer/audio_engine/README.md +9 -0
  85. package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +266 -0
  86. package/src/synthetizer/audio_engine/engine_components/controller_tables.js +88 -0
  87. package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +150 -0
  88. package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/lfo.js +9 -6
  89. package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +282 -0
  90. package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +467 -0
  91. package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +181 -0
  92. package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/modulator_curves.js +33 -30
  93. package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +221 -0
  94. package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +120 -0
  95. package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/unit_converter.js +11 -4
  96. package/src/synthetizer/audio_engine/engine_components/voice.js +519 -0
  97. package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +401 -0
  98. package/src/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +263 -0
  99. package/src/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +132 -0
  100. package/src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +48 -0
  101. package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +241 -0
  102. package/src/synthetizer/audio_engine/engine_methods/create_midi_channel.js +27 -0
  103. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +253 -0
  104. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +66 -0
  105. package/src/synthetizer/audio_engine/engine_methods/mute_channel.js +17 -0
  106. package/src/synthetizer/audio_engine/engine_methods/note_on.js +175 -0
  107. package/src/synthetizer/audio_engine/engine_methods/portamento_time.js +92 -0
  108. package/src/synthetizer/audio_engine/engine_methods/program_change.js +61 -0
  109. package/src/synthetizer/audio_engine/engine_methods/render_voice.js +196 -0
  110. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +30 -0
  111. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +22 -0
  112. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +28 -0
  113. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +31 -0
  114. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +21 -0
  115. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +20 -0
  116. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +55 -0
  117. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +16 -0
  118. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +30 -0
  119. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +63 -0
  120. package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +776 -0
  121. package/src/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +24 -0
  122. package/src/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +33 -0
  123. package/src/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +31 -0
  124. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +15 -0
  125. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +27 -0
  126. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +19 -0
  127. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +27 -0
  128. package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +15 -0
  129. package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +34 -0
  130. package/src/synthetizer/audio_engine/main_processor.js +804 -0
  131. package/src/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +15 -0
  132. package/src/synthetizer/audio_engine/snapshot/channel_snapshot.js +175 -0
  133. package/src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +116 -0
  134. package/src/synthetizer/synth_constants.js +22 -0
  135. package/{spessasynth_core → src}/utils/README.md +1 -0
  136. package/src/utils/buffer_to_wav.js +185 -0
  137. package/src/utils/byte_functions/big_endian.js +32 -0
  138. package/src/utils/byte_functions/little_endian.js +77 -0
  139. package/src/utils/byte_functions/string.js +107 -0
  140. package/src/utils/byte_functions/variable_length_quantity.js +42 -0
  141. package/src/utils/fill_with_defaults.js +21 -0
  142. package/src/utils/indexed_array.js +52 -0
  143. package/{spessasynth_core → src}/utils/loggin.js +70 -78
  144. package/src/utils/other.js +92 -0
  145. package/src/utils/sysex_detector.js +58 -0
  146. package/src/utils/xg_hacks.js +193 -0
  147. package/.idea/inspectionProfiles/Project_Default.xml +0 -10
  148. package/.idea/jsLibraryMappings.xml +0 -6
  149. package/.idea/modules.xml +0 -8
  150. package/.idea/spessasynth_core.iml +0 -12
  151. package/.idea/vcs.xml +0 -6
  152. package/spessasynth_core/midi_parser/README.md +0 -3
  153. package/spessasynth_core/midi_parser/midi_loader.js +0 -386
  154. package/spessasynth_core/sequencer/sequencer.js +0 -202
  155. package/spessasynth_core/sequencer/worklet_sequencer/play.js +0 -209
  156. package/spessasynth_core/sequencer/worklet_sequencer/process_event.js +0 -120
  157. package/spessasynth_core/sequencer/worklet_sequencer/song_control.js +0 -112
  158. package/spessasynth_core/soundfont/README.md +0 -4
  159. package/spessasynth_core/soundfont/chunk/generators.js +0 -205
  160. package/spessasynth_core/soundfont/chunk/modulators.js +0 -232
  161. package/spessasynth_core/soundfont/chunk/presets.js +0 -264
  162. package/spessasynth_core/soundfont/chunk/riff_chunk.js +0 -46
  163. package/spessasynth_core/soundfont/chunk/samples.js +0 -250
  164. package/spessasynth_core/soundfont/soundfont_parser.js +0 -301
  165. package/spessasynth_core/synthetizer/README.md +0 -6
  166. package/spessasynth_core/synthetizer/synthesizer.js +0 -313
  167. package/spessasynth_core/synthetizer/worklet_system/README.md +0 -3
  168. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/controller_control.js +0 -290
  169. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/data_entry.js +0 -280
  170. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/note_off.js +0 -102
  171. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/note_on.js +0 -77
  172. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/program_control.js +0 -140
  173. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/system_exclusive.js +0 -266
  174. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/tuning_control.js +0 -104
  175. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/vibrato_control.js +0 -29
  176. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/voice_control.js +0 -223
  177. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +0 -133
  178. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/modulation_envelope.js +0 -73
  179. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +0 -76
  180. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/volume_envelope.js +0 -272
  181. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/wavetable_oscillator.js +0 -83
  182. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_modulator.js +0 -175
  183. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +0 -106
  184. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +0 -285
  185. package/spessasynth_core/utils/buffer_to_wav.js +0 -70
  186. package/spessasynth_core/utils/byte_functions.js +0 -141
  187. package/spessasynth_core/utils/other.js +0 -49
  188. package/spessasynth_core/utils/shiftable_array.js +0 -26
  189. package/spessasynth_core/utils/stbvorbis_sync.js +0 -1877
@@ -1,301 +0,0 @@
1
- import {ShiftableByteArray} from "../utils/shiftable_array.js";
2
- import {readSamples} from "./chunk/samples.js";
3
- import { readBytesAsString, readBytesAsUintLittleEndian } from '../utils/byte_functions.js'
4
- import {readGenerators, Generator} from "./chunk/generators.js";
5
- import {readInstrumentZones, InstrumentZone, readPresetZones} from "./chunk/zones.js";
6
- import {Preset, readPresets} from "./chunk/presets.js";
7
- import {readInstruments, Instrument} from "./chunk/instruments.js";
8
- import {readModulators, Modulator} from "./chunk/modulators.js";
9
- import { readRIFFChunk, RiffChunk } from './chunk/riff_chunk.js'
10
- import { consoleColors } from '../utils/other.js'
11
- import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn } from '../utils/loggin.js'
12
-
13
- /**
14
- * soundfont_parser.js
15
- * purpose: parses a soundfont2 file
16
- */
17
-
18
- export class SoundFont2
19
- {
20
- /**
21
- * Initializes a new SoundFont2 Parser and parses the given data array
22
- * @param arrayBuffer {Buffer|ArrayBufferLike|{presets: Preset[], info: Object<string, string>}}
23
- */
24
- constructor(arrayBuffer) {
25
- if(arrayBuffer.presets)
26
- {
27
- this.presets = arrayBuffer.presets;
28
- this.soundFontInfo = arrayBuffer.info;
29
- return;
30
- }
31
- this.dataArray = new ShiftableByteArray(arrayBuffer);
32
- SpessaSynthGroup("%cParsing SoundFont...", consoleColors.info);
33
- if(!this.dataArray)
34
- {
35
- SpessaSynthGroupEnd();
36
- throw new TypeError("No data!");
37
- }
38
-
39
- // read the main chunk
40
- let firstChunk = readRIFFChunk(this.dataArray, false);
41
- this.verifyHeader(firstChunk, "riff");
42
-
43
- this.verifyText(readBytesAsString(this.dataArray,4), "sfbk");
44
-
45
- // INFO
46
- let infoChunk = readRIFFChunk(this.dataArray);
47
- this.verifyHeader(infoChunk, "list");
48
- readBytesAsString(infoChunk.chunkData, 4);
49
-
50
- /**
51
- * @type {Object<string, string>}
52
- */
53
- this.soundFontInfo = {};
54
-
55
- while(infoChunk.chunkData.length > infoChunk.chunkData.currentIndex) {
56
- let chunk = readRIFFChunk(infoChunk.chunkData);
57
- let text;
58
- // special case: ifil
59
- switch (chunk.header.toLowerCase())
60
- {
61
- case "ifil":
62
- text = `${readBytesAsUintLittleEndian(chunk.chunkData, 2)}.${readBytesAsUintLittleEndian(chunk.chunkData, 2)}`;
63
- break;
64
-
65
- case "icmt":
66
- text = readBytesAsString(chunk.chunkData, chunk.chunkData.length, undefined, false);
67
- break;
68
-
69
- default:
70
- text = readBytesAsString(chunk.chunkData, chunk.chunkData.length);
71
- }
72
-
73
- SpessaSynthInfo(`%c"${chunk.header}": %c"${text}"`,
74
- consoleColors.info,
75
- consoleColors.recognized);
76
- this.soundFontInfo[chunk.header] = text;
77
- }
78
-
79
- // SDTA
80
- const sdtaChunk = readRIFFChunk(this.dataArray, false);
81
- this.verifyHeader(sdtaChunk, "list")
82
- this.verifyText(readBytesAsString(this.dataArray, 4), "sdta");
83
-
84
- // smpl
85
- SpessaSynthInfo("%cVerifying smpl chunk...", consoleColors.warn)
86
- let sampleDataChunk = readRIFFChunk(this.dataArray, false);
87
- this.verifyHeader(sampleDataChunk, "smpl");
88
- this.sampleDataStartIndex = this.dataArray.currentIndex;
89
-
90
- SpessaSynthInfo(`%cSkipping sample chunk, length: %c${sdtaChunk.size - 12}`,
91
- consoleColors.info,
92
- consoleColors.value);
93
- this.dataArray.currentIndex += sdtaChunk.size - 12;
94
-
95
- // PDTA
96
- SpessaSynthInfo("%cLoading preset data chunk...", consoleColors.warn)
97
- let presetChunk = readRIFFChunk(this.dataArray);
98
- this.verifyHeader(presetChunk, "list");
99
- readBytesAsString(presetChunk.chunkData, 4);
100
-
101
- // read the hydra chunks
102
- const presetHeadersChunk = readRIFFChunk(presetChunk.chunkData);
103
- this.verifyHeader(presetHeadersChunk, "phdr");
104
-
105
- const presetZonesChunk = readRIFFChunk(presetChunk.chunkData);
106
- this.verifyHeader(presetZonesChunk, "pbag");
107
-
108
- const presetModulatorsChunk = readRIFFChunk(presetChunk.chunkData);
109
- this.verifyHeader(presetModulatorsChunk, "pmod");
110
-
111
- const presetGeneratorsChunk = readRIFFChunk(presetChunk.chunkData);
112
- this.verifyHeader(presetGeneratorsChunk, "pgen");
113
-
114
- const presetInstrumentsChunk = readRIFFChunk(presetChunk.chunkData);
115
- this.verifyHeader(presetInstrumentsChunk, "inst");
116
-
117
- const presetInstrumentZonesChunk = readRIFFChunk(presetChunk.chunkData);
118
- this.verifyHeader(presetInstrumentZonesChunk, "ibag");
119
-
120
- const presetInstrumentModulatorsChunk = readRIFFChunk(presetChunk.chunkData);
121
- this.verifyHeader(presetInstrumentModulatorsChunk, "imod");
122
-
123
- const presetInstrumentGeneratorsChunk = readRIFFChunk(presetChunk.chunkData);
124
- this.verifyHeader(presetInstrumentGeneratorsChunk, "igen");
125
-
126
- const presetSamplesChunk = readRIFFChunk(presetChunk.chunkData);
127
- this.verifyHeader(presetSamplesChunk, "shdr");
128
-
129
- /**
130
- * read all the samples
131
- * (the current index points to start of the smpl chunk)
132
- */
133
- this.dataArray.currentIndex = this.sampleDataStartIndex
134
- this.samples = readSamples(presetSamplesChunk, this.dataArray);
135
-
136
- /**
137
- * read all the instrument generators
138
- * @type {Generator[]}
139
- */
140
- let instrumentGenerators = readGenerators(presetInstrumentGeneratorsChunk);
141
-
142
- /**
143
- * read all the instrument modulators
144
- * @type {Modulator[]}
145
- */
146
- let instrumentModulators = readModulators(presetInstrumentModulatorsChunk);
147
-
148
- /**
149
- * read all the instrument zones
150
- * @type {InstrumentZone[]}
151
- */
152
- let instrumentZones = readInstrumentZones(presetInstrumentZonesChunk,
153
- instrumentGenerators,
154
- instrumentModulators,
155
- this.samples);
156
-
157
- /**
158
- * read all the instruments
159
- * @type {Instrument[]}
160
- */
161
- let instruments = readInstruments(presetInstrumentsChunk, instrumentZones);
162
-
163
- /**
164
- * read all the preset generators
165
- * @type {Generator[]}
166
- */
167
- let presetGenerators = readGenerators(presetGeneratorsChunk);
168
-
169
- /**
170
- * Read all the preset modulatorrs
171
- * @type {Modulator[]}
172
- */
173
- let presetModulators = readModulators(presetModulatorsChunk);
174
-
175
- let presetZones = readPresetZones(presetZonesChunk, presetGenerators, presetModulators, instruments);
176
-
177
- /**
178
- * Finally, read all the presets
179
- * @type {Preset[]}
180
- */
181
- this.presets = readPresets(presetHeadersChunk, presetZones);
182
- this.presets.sort((a, b) => (a.program - b.program) + (a.bank - b.bank));
183
- // preload the first preset
184
- SpessaSynthInfo(`%cParsing finished! %c"${this.soundFontInfo["INAM"]}"%c has %c${this.presets.length} %cpresets,
185
- %c${instruments.length}%c instruments and %c${this.samples.length}%c samples.`,
186
- consoleColors.info,
187
- consoleColors.recognized,
188
- consoleColors.info,
189
- consoleColors.recognized,
190
- consoleColors.info,
191
- consoleColors.recognized,
192
- consoleColors.info,
193
- consoleColors.recognized,
194
- consoleColors.info);
195
- SpessaSynthGroupEnd();
196
- }
197
-
198
- /**
199
- * @param chunk {RiffChunk}
200
- * @param expected {string}
201
- */
202
- verifyHeader(chunk, expected)
203
- {
204
- if(chunk.header.toLowerCase() !== expected.toLowerCase())
205
- {
206
- SpessaSynthGroupEnd();
207
- throw new SyntaxError(`Invalid chunk header! Expected "${expected.toLowerCase()}" got "${chunk.header.toLowerCase()}"`);
208
- }
209
- }
210
-
211
- /**
212
- * @param text {string}
213
- * @param expected {string}
214
- */
215
- verifyText(text, expected)
216
- {
217
- if(text.toLowerCase() !== expected.toLowerCase())
218
- {
219
- SpessaSynthGroupEnd();
220
- throw new SyntaxError(`Invalid soundFont! Expected "${expected.toLowerCase()}" got "${text.toLowerCase()}"`);
221
- }
222
- }
223
-
224
- /**
225
- * Get the appropriate preset
226
- * @param bankNr {number}
227
- * @param presetNr {number}
228
- * @returns {Preset}
229
- */
230
- getPreset(bankNr, presetNr) {
231
- let preset = this.presets.find(p => p.bank === bankNr && p.program === presetNr);
232
- if (!preset)
233
- {
234
- preset = this.presets.find(p => p.program === presetNr && p.bank !== 128);
235
- if(bankNr === 128)
236
- {
237
- preset = this.presets.find(p => p.bank === 128 && p.program === presetNr);
238
- if(!preset)
239
- {
240
- preset = this.presets.find(p => p.bank === 128);
241
- }
242
- }
243
- if(preset) {
244
- SpessaSynthWarn(`%cPreset ${bankNr}.${presetNr} not found. Replaced with %c${preset.presetName} (${preset.bank}.${preset.program})`,
245
- consoleColors.warn,
246
- consoleColors.recognized);
247
- }
248
- }
249
- if(!preset)
250
- {
251
- SpessaSynthWarn(`Preset ${presetNr} not found. Defaulting to`, this.presets[0].presetName);
252
- preset = this.presets[0];
253
- }
254
- return preset;
255
- }
256
-
257
- /**
258
- * gets preset by name
259
- * @param presetName {string}
260
- * @returns {Preset}
261
- */
262
- getPresetByName(presetName)
263
- {
264
- let preset = this.presets.find(p => p.presetName === presetName);
265
- if(!preset)
266
- {
267
- SpessaSynthWarn("Preset not found. Defaulting to:", this.presets[0].presetName);
268
- preset = this.presets[0];
269
- }
270
- return preset;
271
- }
272
-
273
-
274
- /**
275
- * Merges soundfonts with the given order. Keep in mind that the info chunk is copied from the first one
276
- * @param soundfonts {...SoundFont2} the soundfonts to merge, the first overwrites the last
277
- * @returns {SoundFont2}
278
- */
279
- static mergeSoundfonts(...soundfonts)
280
- {
281
- const mainSf = soundfonts.shift();
282
- /**
283
- * @type {Preset[]}
284
- */
285
- const presets = mainSf.presets;
286
- while(soundfonts.length)
287
- {
288
- const newPresets = soundfonts.shift().presets;
289
- newPresets.forEach(newPreset => {
290
- if(
291
- presets.find(existingPreset => existingPreset.bank === newPreset.bank && existingPreset.program === newPreset.program) === undefined
292
- )
293
- {
294
- presets.push(newPreset);
295
- }
296
- })
297
- }
298
-
299
- return new SoundFont2({presets: presets, info: mainSf.soundFontInfo});
300
- }
301
- }
@@ -1,6 +0,0 @@
1
- ## This is the main synthesizer folder.
2
- The code here is responsible for making the actual sound.
3
- This is the heart of the SpessaSynth library.
4
- Here it's divided into 2 types:
5
- - `native_system` - the old synthesis system with AudioBuffers, only periodically maintained, lacking many features and not supporting modulators. It will be used when the AudioWorklet API cannot be used.
6
- - `worklet_system` - the current synthesis system with AudioWorklets, has all the features and is actively maintained and expanded.
@@ -1,313 +0,0 @@
1
- import {
2
- addNewChannel,
3
- } from './worklet_system/worklet_utilities/worklet_processor_channel.js'
4
-
5
- import { SoundFont2 } from '../soundfont/soundfont_parser.js'
6
- import { systemExclusive } from './worklet_system/worklet_methods/system_exclusive.js'
7
- import { noteOn } from './worklet_system/worklet_methods/note_on.js'
8
- import { dataEntryCoarse, dataEntryFine } from './worklet_system/worklet_methods/data_entry.js'
9
- import { killNote, noteOff, stopAll, stopAllChannels } from './worklet_system/worklet_methods/note_off.js'
10
- import {
11
- controllerChange, muteChannel,
12
- resetAllControllers,
13
- resetControllers,
14
- resetParameters, setMainVolume, setMasterPan,
15
- } from './worklet_system/worklet_methods/controller_control.js'
16
- import {
17
- pitchWheel,
18
- setChannelTuning,
19
- setMasterTuning, setModulationDepth,
20
- transposeAllChannels,
21
- transposeChannel,
22
- } from './worklet_system/worklet_methods/tuning_control.js'
23
- import {
24
- programChange,
25
- reloadSoundFont,
26
- sampleDump,
27
- setDrums,
28
- setPreset,
29
- } from './worklet_system/worklet_methods/program_control.js'
30
- import { disableAndLockVibrato, setVibrato } from './worklet_system/worklet_methods/vibrato_control.js'
31
- import { SpessaSynthInfo } from '../utils/loggin.js'
32
- import { consoleColors } from '../utils/other.js'
33
- import {
34
- PAN_SMOOTHING_FACTOR,
35
- releaseVoice,
36
- renderVoice,
37
- voiceKilling
38
- } from './worklet_system/worklet_methods/voice_control.js'
39
- import {stbvorbis} from "../utils/stbvorbis_sync.js";
40
- import {VOLUME_ENVELOPE_SMOOTHING_FACTOR} from "./worklet_system/worklet_utilities/volume_envelope.js";
41
-
42
-
43
- export const VOICE_CAP = 450;
44
-
45
- export const DEFAULT_PERCUSSION = 9;
46
- export const DEFAULT_CHANNEL_COUNT = 16;
47
- export const DEFAULT_SYNTH_MODE = "gs";
48
-
49
- export const MIN_NOTE_LENGTH = 0.07; // if the note is released faster than that, it forced to last that long
50
-
51
- export const SYNTHESIZER_GAIN = 1.0;
52
-
53
- const BLOCK_SIZE = 128;
54
-
55
- class Synthesizer {
56
- /**
57
- * Creates a new synthesizer
58
- * @param soundFontBuffer {Buffer|ArrayBufferLike} the soundfont file buffer.
59
- * @param sampleRate {number} the sample rate, in hertz.
60
- * @param blockSize {number} the block size in samples, represets the interval of updating the sequencer, modulation envelope, etc. Defaults to 128.
61
- */
62
- constructor(soundFontBuffer, sampleRate, blockSize = BLOCK_SIZE) {
63
-
64
- this.currentTime = 0;
65
- this.sampleRate = sampleRate;
66
- this.blockSize = blockSize;
67
-
68
- this._outputsAmount = DEFAULT_CHANNEL_COUNT;
69
-
70
- /**
71
- * @type {function}
72
- */
73
- this.processTickCallback = undefined;
74
-
75
- this.transposition = 0;
76
-
77
- /**
78
- * The volume gain
79
- * @type {number}
80
- */
81
- this.mainVolume = SYNTHESIZER_GAIN;
82
-
83
- /**
84
- * -1 to 1
85
- * @type {number}
86
- */
87
- this.pan = 0.0;
88
- /**
89
- * the pan of the left channel
90
- * @type {number}
91
- */
92
- this.panLeft = 0.5 * this.mainVolume;
93
-
94
- this.highPerformanceMode = false;
95
-
96
- /**
97
- * If using sf3 soundfonts, wait for this promise
98
- * @type {Promise<unknown>}
99
- */
100
- this.sf3supportReady = stbvorbis.isReady;
101
-
102
- /**
103
- * the pan of the right channel
104
- * @type {number}
105
- */
106
- this.panRight = 0.5 * this.mainVolume;
107
- /**
108
- * @type {SoundFont2}
109
- */
110
- this.soundfont = new SoundFont2(soundFontBuffer);
111
-
112
- this.defaultPreset = this.soundfont.getPreset(0, 0);
113
- this.drumPreset = this.soundfont.getPreset(128, 0);
114
-
115
- /**
116
- * @type {Float32Array[]}
117
- */
118
- this.workletDumpedSamplesList = [];
119
- /**
120
- * contains all the channels with their voices on the processor size
121
- * @type {WorkletProcessorChannel[]}
122
- */
123
- this.workletProcessorChannels = [];
124
- for (let i = 0; i < this._outputsAmount; i++) {
125
- this.addNewChannel(false);
126
- }
127
-
128
- this.workletProcessorChannels[DEFAULT_PERCUSSION].preset = this.drumPreset;
129
- this.workletProcessorChannels[DEFAULT_PERCUSSION].drumChannel = true;
130
-
131
- // in seconds, time between two samples (very, very short)
132
- this.sampleTime = 1 / this.sampleRate;
133
-
134
- // these smoothing factors were tested on 44100Hz, adjust them here
135
- this.volumeEnvelopeSmoothingFactor = VOLUME_ENVELOPE_SMOOTHING_FACTOR * (sampleRate / 44100);
136
- this.panSmoothingFactor = PAN_SMOOTHING_FACTOR * (sampleRate / 44100);
137
-
138
- /**
139
- * Controls the system
140
- * @typedef {"gm"|"gm2"|"gs"|"xg"} SynthSystem
141
- * @type {SynthSystem}
142
- */
143
- this.system = DEFAULT_SYNTH_MODE;
144
-
145
- this.totalVoicesAmount = 0;
146
- SpessaSynthInfo(`%cSpessaSynth is ready!`,
147
- consoleColors.info)
148
- }
149
-
150
- debugMessage()
151
- {
152
- SpessaSynthInfo({
153
- channels: this.workletProcessorChannels,
154
- voicesAmount: this.totalVoicesAmount,
155
- outputAmount: this._outputsAmount,
156
- dumpedSamples: this.workletDumpedSamplesList
157
- });
158
- }
159
-
160
- /**
161
- * @param channel {number}
162
- * @param controllerNumber {number}
163
- * @param isLocked {boolean}
164
- */
165
- lockController(channel, controllerNumber, isLocked)
166
- {
167
- this.workletProcessorChannels[channel].lockedControllers[controllerNumber] = isLocked;
168
- }
169
-
170
- /**
171
- * Syntesizes the voice to output buffers.
172
- * @param outputChannels {Float32Array[]} - the dry audio output data of 2 arrays. The first array is left the second is right.
173
- * @param reverbOutputChannels {Float32Array[]} - the dry audio output data for the reverb of 2 arrays. The first array is left the second is right.
174
- * @param chorusOutputChannels {Float32Array[]} - the dry audio output data for the chorus of 2 arrays. The first array is left the second is right.
175
- */
176
- render(outputChannels, reverbOutputChannels = undefined, chorusOutputChannels = undefined) {
177
- // render in blocks until we reach the output
178
- let samplesToRender = outputChannels[0].length;
179
- let renderedSamples = 0;
180
- while(samplesToRender > 0)
181
- {
182
- /**
183
- * @type {Float32Array[]}
184
- */
185
- let block;
186
- let reverbBlock;
187
- let chorusBlock;
188
- if(samplesToRender < this.blockSize)
189
- {
190
- block = [new Float32Array(samplesToRender), new Float32Array(samplesToRender)];
191
- reverbBlock = [new Float32Array(samplesToRender), new Float32Array(samplesToRender)];
192
- chorusBlock = [new Float32Array(samplesToRender), new Float32Array(samplesToRender)];
193
- }
194
- else
195
- {
196
- block = [new Float32Array(this.blockSize), new Float32Array(this.blockSize)];
197
- chorusBlock = [new Float32Array(this.blockSize), new Float32Array(this.blockSize)];
198
- reverbBlock = [new Float32Array(this.blockSize), new Float32Array(this.blockSize)];
199
- }
200
- samplesToRender -= this.blockSize;
201
- // for every channel
202
- let totalCurrentVoices = 0;
203
- this.workletProcessorChannels.forEach(channel => {
204
- if(channel.voices.length < 1 || channel.isMuted)
205
- {
206
- // skip the channels
207
- return;
208
- }
209
- const tempV = channel.voices;
210
-
211
- // reset voices
212
- channel.voices = [];
213
-
214
- // for every voice
215
- tempV.forEach(v => {
216
- // render voice
217
- this.renderVoice(channel, v, block, reverbBlock, chorusBlock);
218
- if(!v.finished)
219
- {
220
- // if not finished, add it back
221
- channel.voices.push(v);
222
- }
223
- });
224
-
225
- totalCurrentVoices += tempV.length;
226
- });
227
-
228
- // if voice count changed, update voice amount
229
- if(totalCurrentVoices !== this.totalVoicesAmount)
230
- {
231
- this.totalVoicesAmount = totalCurrentVoices;
232
- }
233
-
234
- // if sequencer connected, process
235
- if(this.processTickCallback)
236
- {
237
- this.processTickCallback();
238
- }
239
- // append to blocks
240
- outputChannels[0].set(block[0], renderedSamples);
241
- outputChannels[1].set(block[1], renderedSamples);
242
-
243
- if(reverbOutputChannels)
244
- {
245
- reverbOutputChannels[0].set(reverbBlock[0], renderedSamples);
246
- reverbOutputChannels[1].set(reverbBlock[1], renderedSamples);
247
- }
248
-
249
- if(chorusOutputChannels)
250
- {
251
- chorusOutputChannels[1].set(chorusBlock[1], renderedSamples);
252
- chorusOutputChannels[1].set(chorusBlock[1], renderedSamples);
253
- }
254
-
255
- renderedSamples += block[0].length;
256
- this.currentTime += this.sampleTime * block[0].length;
257
- }
258
- }
259
- }
260
-
261
- // include other methods
262
- // voice related
263
- Synthesizer.prototype.renderVoice = renderVoice;
264
- Synthesizer.prototype.releaseVoice = releaseVoice;
265
- Synthesizer.prototype.voiceKilling = voiceKilling;
266
-
267
- // system exlcusive related
268
- Synthesizer.prototype.systemExclusive = systemExclusive;
269
-
270
- // note messages related
271
- Synthesizer.prototype.noteOn = noteOn;
272
- Synthesizer.prototype.noteOff = noteOff;
273
- Synthesizer.prototype.killNote = killNote;
274
- Synthesizer.prototype.stopAll = stopAll;
275
- Synthesizer.prototype.stopAllChannels = stopAllChannels;
276
- Synthesizer.prototype.muteChannel = muteChannel;
277
-
278
- // vustom vibrato related
279
- Synthesizer.prototype.setVibrato = setVibrato;
280
- Synthesizer.prototype.disableAndLockVibrato = disableAndLockVibrato;
281
-
282
- // data entry related
283
- Synthesizer.prototype.dataEntryCoarse = dataEntryCoarse;
284
- Synthesizer.prototype.dataEntryFine = dataEntryFine;
285
-
286
- // channel related
287
- Synthesizer.prototype.addNewChannel = addNewChannel;
288
- Synthesizer.prototype.controllerChange = controllerChange;
289
- Synthesizer.prototype.resetAllControllers = resetAllControllers;
290
- Synthesizer.prototype.resetControllers = resetControllers;
291
- Synthesizer.prototype.resetParameters = resetParameters;
292
-
293
- // master parameter related
294
- Synthesizer.prototype.setMainVolume = setMainVolume;
295
- Synthesizer.prototype.setMasterPan = setMasterPan;
296
-
297
- // tuning related
298
- Synthesizer.prototype.transposeAllChannels = transposeAllChannels;
299
- Synthesizer.prototype.transposeChannel = transposeChannel;
300
- Synthesizer.prototype.setChannelTuning = setChannelTuning;
301
- Synthesizer.prototype.setMasterTuning = setMasterTuning;
302
- Synthesizer.prototype.setModulationDepth = setModulationDepth;
303
- Synthesizer.prototype.pitchWheel = pitchWheel;
304
-
305
- // program related
306
- Synthesizer.prototype.programChange = programChange;
307
- Synthesizer.prototype.setPreset = setPreset;
308
- Synthesizer.prototype.setDrums = setDrums;
309
- Synthesizer.prototype.reloadSoundFont = reloadSoundFont;
310
- Synthesizer.prototype.sampleDump = sampleDump;
311
-
312
-
313
- export { Synthesizer }
@@ -1,3 +0,0 @@
1
- ## This the worklet system synthesis folder.
2
- The code here is responsible for a single midi channel, synthesizing the sound to it.
3
- `worklet_utilities` contains the various digital signal processing functions such as the wavetable oscillator, low pass filter, etc.