spessasynth_core 1.1.2 → 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 -303
  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 -222
  177. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +0 -95
  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 -194
  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 -173
  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 -313
  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,303 +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 { releaseVoice, renderVoice, voiceKilling } from './worklet_system/worklet_methods/voice_control.js'
34
- import {stbvorbis} from "../utils/stbvorbis_sync.js";
35
-
36
-
37
- export const VOICE_CAP = 450;
38
-
39
- export const DEFAULT_PERCUSSION = 9;
40
- export const DEFAULT_CHANNEL_COUNT = 16;
41
- export const DEFAULT_SYNTH_MODE = "gs";
42
-
43
- export const MIN_NOTE_LENGTH = 0.07; // if the note is released faster than that, it forced to last that long
44
-
45
- export const SYNTHESIZER_GAIN = 1.0;
46
-
47
- const BLOCK_SIZE = 128;
48
-
49
- class Synthesizer {
50
- /**
51
- * Creates a new synthesizer
52
- * @param soundFontBuffer {Buffer|ArrayBufferLike} the soundfont file buffer.
53
- * @param sampleRate {number} the sample rate, in hertz.
54
- * @param blockSize {number} the block size in samples, represets the interval of updating the sequencer, modulation envelope, etc. Defaults to 128.
55
- */
56
- constructor(soundFontBuffer, sampleRate, blockSize = BLOCK_SIZE) {
57
-
58
- this.currentTime = 0;
59
- this.sampleRate = sampleRate;
60
- this.blockSize = blockSize;
61
-
62
- this._outputsAmount = DEFAULT_CHANNEL_COUNT;
63
-
64
- /**
65
- * @type {function}
66
- */
67
- this.processTickCallback = undefined;
68
-
69
- this.transposition = 0;
70
-
71
- /**
72
- * The volume gain
73
- * @type {number}
74
- */
75
- this.mainVolume = SYNTHESIZER_GAIN;
76
-
77
- /**
78
- * -1 to 1
79
- * @type {number}
80
- */
81
- this.pan = 0.0;
82
- /**
83
- * the pan of the left channel
84
- * @type {number}
85
- */
86
- this.panLeft = 0.5 * this.mainVolume;
87
-
88
- this.highPerformanceMode = false;
89
-
90
- /**
91
- * If using sf3 soundfonts, wait for this promise
92
- * @type {Promise<unknown>}
93
- */
94
- this.sf3supportReady = stbvorbis.isReady;
95
-
96
- /**
97
- * the pan of the right channel
98
- * @type {number}
99
- */
100
- this.panRight = 0.5 * this.mainVolume;
101
- /**
102
- * @type {SoundFont2}
103
- */
104
- this.soundfont = new SoundFont2(soundFontBuffer);
105
-
106
- this.defaultPreset = this.soundfont.getPreset(0, 0);
107
- this.drumPreset = this.soundfont.getPreset(128, 0);
108
-
109
- /**
110
- * @type {Float32Array[]}
111
- */
112
- this.workletDumpedSamplesList = [];
113
- /**
114
- * contains all the channels with their voices on the processor size
115
- * @type {WorkletProcessorChannel[]}
116
- */
117
- this.workletProcessorChannels = [];
118
- for (let i = 0; i < this._outputsAmount; i++) {
119
- this.addNewChannel(false);
120
- }
121
-
122
- this.workletProcessorChannels[DEFAULT_PERCUSSION].preset = this.drumPreset;
123
- this.workletProcessorChannels[DEFAULT_PERCUSSION].drumChannel = true;
124
-
125
- // in seconds, time between two samples (very, very short)
126
- this.sampleTime = 1 / this.sampleRate;
127
-
128
- /**
129
- * Controls the system
130
- * @typedef {"gm"|"gm2"|"gs"|"xg"} SynthSystem
131
- * @type {SynthSystem}
132
- */
133
- this.system = DEFAULT_SYNTH_MODE;
134
-
135
- this.totalVoicesAmount = 0;
136
- SpessaSynthInfo(`%cSpessaSynth is ready!`,
137
- consoleColors.info)
138
- }
139
-
140
- debugMessage()
141
- {
142
- SpessaSynthInfo({
143
- channels: this.workletProcessorChannels,
144
- voicesAmount: this.totalVoicesAmount,
145
- outputAmount: this._outputsAmount,
146
- dumpedSamples: this.workletDumpedSamplesList
147
- });
148
- }
149
-
150
- /**
151
- * @param channel {number}
152
- * @param controllerNumber {number}
153
- * @param isLocked {boolean}
154
- */
155
- lockController(channel, controllerNumber, isLocked)
156
- {
157
- this.workletProcessorChannels[channel].lockedControllers[controllerNumber] = isLocked;
158
- }
159
-
160
- /**
161
- * Syntesizes the voice to output buffers.
162
- * @param outputChannels {Float32Array[]} - the dry audio output data of 2 arrays. The first array is left the second is right.
163
- * @param reverbOutputChannels {Float32Array[]} - the dry audio output data for the reverb of 2 arrays. The first array is left the second is right.
164
- * @param chorusOutputChannels {Float32Array[]} - the dry audio output data for the chorus of 2 arrays. The first array is left the second is right.
165
- */
166
- render(outputChannels, reverbOutputChannels = undefined, chorusOutputChannels = undefined) {
167
- // render in blocks until we reach the output
168
- let samplesToRender = outputChannels[0].length;
169
- let renderedSamples = 0;
170
- while(samplesToRender > 0)
171
- {
172
- /**
173
- * @type {Float32Array[]}
174
- */
175
- let block;
176
- let reverbBlock;
177
- let chorusBlock;
178
- if(samplesToRender < this.blockSize)
179
- {
180
- block = [new Float32Array(samplesToRender), new Float32Array(samplesToRender)];
181
- reverbBlock = [new Float32Array(samplesToRender), new Float32Array(samplesToRender)];
182
- chorusBlock = [new Float32Array(samplesToRender), new Float32Array(samplesToRender)];
183
- }
184
- else
185
- {
186
- block = [new Float32Array(this.blockSize), new Float32Array(this.blockSize)];
187
- chorusBlock = [new Float32Array(this.blockSize), new Float32Array(this.blockSize)];
188
- reverbBlock = [new Float32Array(this.blockSize), new Float32Array(this.blockSize)];
189
- }
190
- samplesToRender -= this.blockSize;
191
- // for every channel
192
- let totalCurrentVoices = 0;
193
- this.workletProcessorChannels.forEach(channel => {
194
- if(channel.voices.length < 1 || channel.isMuted)
195
- {
196
- // skip the channels
197
- return;
198
- }
199
- const tempV = channel.voices;
200
-
201
- // reset voices
202
- channel.voices = [];
203
-
204
- // for every voice
205
- tempV.forEach(v => {
206
- // render voice
207
- this.renderVoice(channel, v, block, reverbBlock, chorusBlock);
208
- if(!v.finished)
209
- {
210
- // if not finished, add it back
211
- channel.voices.push(v);
212
- }
213
- });
214
-
215
- totalCurrentVoices += tempV.length;
216
- });
217
-
218
- // if voice count changed, update voice amount
219
- if(totalCurrentVoices !== this.totalVoicesAmount)
220
- {
221
- this.totalVoicesAmount = totalCurrentVoices;
222
- }
223
-
224
- // if sequencer connected, process
225
- if(this.processTickCallback)
226
- {
227
- this.processTickCallback();
228
- }
229
- // append to blocks
230
- outputChannels[0].set(block[0], renderedSamples);
231
- outputChannels[1].set(block[1], renderedSamples);
232
-
233
- if(reverbOutputChannels)
234
- {
235
- reverbOutputChannels[0].set(reverbBlock[0], renderedSamples);
236
- reverbOutputChannels[1].set(reverbBlock[1], renderedSamples);
237
- }
238
-
239
- if(chorusOutputChannels)
240
- {
241
- chorusOutputChannels[1].set(chorusBlock[1], renderedSamples);
242
- chorusOutputChannels[1].set(chorusBlock[1], renderedSamples);
243
- }
244
-
245
- renderedSamples += block[0].length;
246
- this.currentTime += this.sampleTime * block[0].length;
247
- }
248
- }
249
- }
250
-
251
- // include other methods
252
- // voice related
253
- Synthesizer.prototype.renderVoice = renderVoice;
254
- Synthesizer.prototype.releaseVoice = releaseVoice;
255
- Synthesizer.prototype.voiceKilling = voiceKilling;
256
-
257
- // system exlcusive related
258
- Synthesizer.prototype.systemExclusive = systemExclusive;
259
-
260
- // note messages related
261
- Synthesizer.prototype.noteOn = noteOn;
262
- Synthesizer.prototype.noteOff = noteOff;
263
- Synthesizer.prototype.killNote = killNote;
264
- Synthesizer.prototype.stopAll = stopAll;
265
- Synthesizer.prototype.stopAllChannels = stopAllChannels;
266
- Synthesizer.prototype.muteChannel = muteChannel;
267
-
268
- // vustom vibrato related
269
- Synthesizer.prototype.setVibrato = setVibrato;
270
- Synthesizer.prototype.disableAndLockVibrato = disableAndLockVibrato;
271
-
272
- // data entry related
273
- Synthesizer.prototype.dataEntryCoarse = dataEntryCoarse;
274
- Synthesizer.prototype.dataEntryFine = dataEntryFine;
275
-
276
- // channel related
277
- Synthesizer.prototype.addNewChannel = addNewChannel;
278
- Synthesizer.prototype.controllerChange = controllerChange;
279
- Synthesizer.prototype.resetAllControllers = resetAllControllers;
280
- Synthesizer.prototype.resetControllers = resetControllers;
281
- Synthesizer.prototype.resetParameters = resetParameters;
282
-
283
- // master parameter related
284
- Synthesizer.prototype.setMainVolume = setMainVolume;
285
- Synthesizer.prototype.setMasterPan = setMasterPan;
286
-
287
- // tuning related
288
- Synthesizer.prototype.transposeAllChannels = transposeAllChannels;
289
- Synthesizer.prototype.transposeChannel = transposeChannel;
290
- Synthesizer.prototype.setChannelTuning = setChannelTuning;
291
- Synthesizer.prototype.setMasterTuning = setMasterTuning;
292
- Synthesizer.prototype.setModulationDepth = setModulationDepth;
293
- Synthesizer.prototype.pitchWheel = pitchWheel;
294
-
295
- // program related
296
- Synthesizer.prototype.programChange = programChange;
297
- Synthesizer.prototype.setPreset = setPreset;
298
- Synthesizer.prototype.setDrums = setDrums;
299
- Synthesizer.prototype.reloadSoundFont = reloadSoundFont;
300
- Synthesizer.prototype.sampleDump = sampleDump;
301
-
302
-
303
- 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.