spessasynth_lib 3.25.22 → 3.26.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 (168) hide show
  1. package/README.md +29 -114
  2. package/index.js +33 -33
  3. package/package.json +16 -6
  4. package/external_midi/README.md +0 -4
  5. package/external_midi/midi_handler.js +0 -130
  6. package/external_midi/web_midi_link.js +0 -43
  7. package/externals/fflate/LICENSE +0 -21
  8. package/externals/fflate/fflate.min.js +0 -1
  9. package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  10. package/externals/stbvorbis_sync/LICENSE +0 -202
  11. package/externals/stbvorbis_sync/NOTICE +0 -6
  12. package/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  13. package/midi/README.md +0 -32
  14. package/midi/basic_midi.js +0 -565
  15. package/midi/midi_builder.js +0 -202
  16. package/midi/midi_data.js +0 -63
  17. package/midi/midi_loader.js +0 -324
  18. package/midi/midi_message.js +0 -254
  19. package/midi/midi_sequence.js +0 -225
  20. package/midi/midi_tools/get_note_times.js +0 -154
  21. package/midi/midi_tools/midi_editor.js +0 -611
  22. package/midi/midi_tools/midi_writer.js +0 -99
  23. package/midi/midi_tools/rmidi_writer.js +0 -567
  24. package/midi/midi_tools/used_keys_loaded.js +0 -238
  25. package/midi/xmf_loader.js +0 -454
  26. package/sequencer/README.md +0 -32
  27. package/sequencer/sequencer_engine/events.js +0 -207
  28. package/sequencer/sequencer_engine/play.js +0 -353
  29. package/sequencer/sequencer_engine/process_event.js +0 -169
  30. package/sequencer/sequencer_engine/process_tick.js +0 -106
  31. package/sequencer/sequencer_engine/sequencer_engine.js +0 -337
  32. package/sequencer/sequencer_engine/song_control.js +0 -229
  33. package/sequencer/worklet_wrapper/default_sequencer_options.js +0 -8
  34. package/sequencer/worklet_wrapper/sequencer.js +0 -807
  35. package/sequencer/worklet_wrapper/sequencer_message.js +0 -53
  36. package/soundfont/README.md +0 -13
  37. package/soundfont/basic_soundfont/basic_instrument.js +0 -77
  38. package/soundfont/basic_soundfont/basic_preset.js +0 -336
  39. package/soundfont/basic_soundfont/basic_sample.js +0 -197
  40. package/soundfont/basic_soundfont/basic_soundfont.js +0 -565
  41. package/soundfont/basic_soundfont/basic_zone.js +0 -64
  42. package/soundfont/basic_soundfont/basic_zones.js +0 -43
  43. package/soundfont/basic_soundfont/generator.js +0 -220
  44. package/soundfont/basic_soundfont/modulator.js +0 -378
  45. package/soundfont/basic_soundfont/riff_chunk.js +0 -149
  46. package/soundfont/basic_soundfont/write_dls/art2.js +0 -173
  47. package/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  48. package/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -400
  49. package/soundfont/basic_soundfont/write_dls/ins.js +0 -103
  50. package/soundfont/basic_soundfont/write_dls/lins.js +0 -18
  51. package/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  52. package/soundfont/basic_soundfont/write_dls/rgn2.js +0 -121
  53. package/soundfont/basic_soundfont/write_dls/wave.js +0 -94
  54. package/soundfont/basic_soundfont/write_dls/write_dls.js +0 -119
  55. package/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  56. package/soundfont/basic_soundfont/write_dls/wvpl.js +0 -32
  57. package/soundfont/basic_soundfont/write_sf2/ibag.js +0 -39
  58. package/soundfont/basic_soundfont/write_sf2/igen.js +0 -80
  59. package/soundfont/basic_soundfont/write_sf2/imod.js +0 -46
  60. package/soundfont/basic_soundfont/write_sf2/inst.js +0 -34
  61. package/soundfont/basic_soundfont/write_sf2/pbag.js +0 -39
  62. package/soundfont/basic_soundfont/write_sf2/pgen.js +0 -82
  63. package/soundfont/basic_soundfont/write_sf2/phdr.js +0 -42
  64. package/soundfont/basic_soundfont/write_sf2/pmod.js +0 -46
  65. package/soundfont/basic_soundfont/write_sf2/sdta.js +0 -80
  66. package/soundfont/basic_soundfont/write_sf2/shdr.js +0 -55
  67. package/soundfont/basic_soundfont/write_sf2/write.js +0 -222
  68. package/soundfont/dls/articulator_converter.js +0 -396
  69. package/soundfont/dls/dls_destinations.js +0 -38
  70. package/soundfont/dls/dls_preset.js +0 -44
  71. package/soundfont/dls/dls_sample.js +0 -75
  72. package/soundfont/dls/dls_soundfont.js +0 -186
  73. package/soundfont/dls/dls_sources.js +0 -62
  74. package/soundfont/dls/dls_zone.js +0 -95
  75. package/soundfont/dls/read_articulation.js +0 -299
  76. package/soundfont/dls/read_instrument.js +0 -121
  77. package/soundfont/dls/read_instrument_list.js +0 -17
  78. package/soundfont/dls/read_lart.js +0 -35
  79. package/soundfont/dls/read_region.js +0 -152
  80. package/soundfont/dls/read_samples.js +0 -270
  81. package/soundfont/load_soundfont.js +0 -21
  82. package/soundfont/read_sf2/generators.js +0 -46
  83. package/soundfont/read_sf2/instruments.js +0 -66
  84. package/soundfont/read_sf2/modulators.js +0 -36
  85. package/soundfont/read_sf2/presets.js +0 -80
  86. package/soundfont/read_sf2/samples.js +0 -304
  87. package/soundfont/read_sf2/soundfont.js +0 -305
  88. package/soundfont/read_sf2/zones.js +0 -263
  89. package/synthetizer/README.md +0 -10
  90. package/synthetizer/audio_effects/effects_config.js +0 -25
  91. package/synthetizer/audio_effects/fancy_chorus.js +0 -162
  92. package/synthetizer/audio_effects/rb_compressed.min.js +0 -1
  93. package/synthetizer/audio_effects/reverb.js +0 -35
  94. package/synthetizer/audio_effects/reverb_as_binary.js +0 -18
  95. package/synthetizer/audio_engine/README.md +0 -25
  96. package/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -266
  97. package/synthetizer/audio_engine/engine_components/controller_tables.js +0 -88
  98. package/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -149
  99. package/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  100. package/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  101. package/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -471
  102. package/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  103. package/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  104. package/synthetizer/audio_engine/engine_components/soundfont_manager/sfman_message.js +0 -9
  105. package/synthetizer/audio_engine/engine_components/soundfont_manager/soundfont_manager.js +0 -254
  106. package/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -120
  107. package/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  108. package/synthetizer/audio_engine/engine_components/voice.js +0 -519
  109. package/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -401
  110. package/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -263
  111. package/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -132
  112. package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
  113. package/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -241
  114. package/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -27
  115. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -253
  116. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -66
  117. package/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  118. package/synthetizer/audio_engine/engine_methods/note_on.js +0 -174
  119. package/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  120. package/synthetizer/audio_engine/engine_methods/program_change.js +0 -61
  121. package/synthetizer/audio_engine/engine_methods/render_voice.js +0 -196
  122. package/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -30
  123. package/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
  124. package/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +0 -40
  125. package/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +0 -34
  126. package/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -21
  127. package/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -20
  128. package/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -55
  129. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  130. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  131. package/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  132. package/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -744
  133. package/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -24
  134. package/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -33
  135. package/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -31
  136. package/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  137. package/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -27
  138. package/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  139. package/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  140. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  141. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  142. package/synthetizer/audio_engine/main_processor.js +0 -765
  143. package/synthetizer/audio_engine/message_protocol/README.md +0 -13
  144. package/synthetizer/audio_engine/message_protocol/message_sending.js +0 -22
  145. package/synthetizer/audio_engine/message_protocol/worklet_message.js +0 -107
  146. package/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -14
  147. package/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  148. package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -122
  149. package/synthetizer/synth_constants.js +0 -20
  150. package/synthetizer/worklet_processor.min.js +0 -21
  151. package/synthetizer/worklet_wrapper/key_modifier_manager.js +0 -104
  152. package/synthetizer/worklet_wrapper/synth_event_handler.js +0 -214
  153. package/synthetizer/worklet_wrapper/synth_soundfont_manager.js +0 -111
  154. package/synthetizer/worklet_wrapper/synthetizer.js +0 -1027
  155. package/synthetizer/worklet_wrapper/worklet_processor.js +0 -340
  156. package/synthetizer/worklet_wrapper/worklet_url.js +0 -16
  157. package/utils/README.md +0 -5
  158. package/utils/buffer_to_wav.js +0 -186
  159. package/utils/byte_functions/big_endian.js +0 -32
  160. package/utils/byte_functions/little_endian.js +0 -77
  161. package/utils/byte_functions/string.js +0 -107
  162. package/utils/byte_functions/variable_length_quantity.js +0 -42
  163. package/utils/fill_with_defaults.js +0 -21
  164. package/utils/indexed_array.js +0 -52
  165. package/utils/loggin.js +0 -79
  166. package/utils/other.js +0 -92
  167. package/utils/sysex_detector.js +0 -58
  168. package/utils/xg_hacks.js +0 -193
@@ -1,340 +0,0 @@
1
- import { consoleColors } from "../../utils/other.js";
2
- import { SpessaSynthInfo, SpessaSynthLogging, SpessaSynthWarn } from "../../utils/loggin.js";
3
- import { SpessaSynthProcessor } from "../audio_engine/main_processor.js";
4
- import {
5
- ALL_CHANNELS_OR_DIFFERENT_ACTION,
6
- returnMessageType,
7
- workletMessageType
8
- } from "../audio_engine/message_protocol/worklet_message.js";
9
- import { SynthesizerSnapshot } from "../audio_engine/snapshot/synthesizer_snapshot.js";
10
- import { WORKLET_PROCESSOR_NAME } from "./worklet_url.js";
11
- import { MIDI_CHANNEL_COUNT } from "../synth_constants.js";
12
- import { workletKeyModifierMessageType } from "../audio_engine/engine_components/key_modifier_manager.js";
13
- import { masterParameterType } from "../audio_engine/engine_methods/controller_control/master_parameters.js";
14
-
15
-
16
- // a worklet processor wrapper for the synthesizer core
17
- class WorkletSpessaProcessor extends AudioWorkletProcessor
18
- {
19
- /**
20
- * If the worklet is alive
21
- * @type {boolean}
22
- */
23
- alive = true;
24
-
25
- /**
26
- * Instead of 18 stereo outputs, there's one with 32 channels (no effects)
27
- * @type {boolean}
28
- */
29
- oneOutputMode = false;
30
-
31
- /**
32
- * Creates a new worklet synthesis system. contains all channels
33
- * @param options {{
34
- * processorOptions: {
35
- * midiChannels: number,
36
- * soundfont: ArrayBuffer,
37
- * enableEventSystem: boolean,
38
- * startRenderingData: StartRenderingDataConfig
39
- * }}}
40
- */
41
- constructor(options)
42
- {
43
- super();
44
- const opts = options.processorOptions;
45
-
46
-
47
- // one output is indicated by setting midiChannels to 1
48
- this.oneOutputMode = opts.midiChannels === 1;
49
-
50
- // noinspection JSUnresolvedReference
51
- /**
52
- * Initialize the synthesis engine
53
- * @type {SpessaSynthProcessor}
54
- */
55
- this.synthesizer = new SpessaSynthProcessor(
56
- MIDI_CHANNEL_COUNT, // midi channel count (16)
57
- opts.soundfont, // initial sound bank
58
- sampleRate, // AudioWorkletGlobalScope
59
- this.postMessageToMainThread.bind(this), // connect to message port
60
- !this.oneOutputMode, // one output mode disables effects
61
- opts?.enableEventSystem, // enable message port?
62
- opts?.startRenderingData, // start rendering?
63
- currentTime // AudioWorkletGlobalScope, sync with audioContext time
64
- );
65
-
66
- // receive messages from the main thread
67
- this.port.onmessage = e => this.handleMessage(e.data);
68
- }
69
-
70
- /**
71
- * @param data {WorkletReturnMessage}
72
- */
73
- postMessageToMainThread(data)
74
- {
75
- this.port.postMessage(data);
76
- }
77
-
78
- /**
79
- * @this {WorkletSpessaProcessor}
80
- * @param message {WorkletMessage}
81
- */
82
- handleMessage(message)
83
- {
84
- const data = message.messageData;
85
- const channel = message.channelNumber;
86
- /**
87
- * @type {MidiAudioChannel}
88
- */
89
- let channelObject;
90
- if (channel >= 0)
91
- {
92
- channelObject = this.synthesizer.midiAudioChannels[channel];
93
- if (channelObject === undefined)
94
- {
95
- SpessaSynthWarn(`Trying to access channel ${channel} which does not exist... ignoring!`);
96
- return;
97
- }
98
- }
99
- switch (message.messageType)
100
- {
101
- case workletMessageType.midiMessage:
102
- this.synthesizer.processMessage(...data);
103
- break;
104
-
105
- case workletMessageType.customcCcChange:
106
- // custom controller change
107
- channelObject.setCustomController(data[0], data[1]);
108
- channelObject.updateChannelTuning();
109
- break;
110
-
111
- case workletMessageType.ccReset:
112
- if (channel === ALL_CHANNELS_OR_DIFFERENT_ACTION)
113
- {
114
- this.synthesizer.resetAllControllers();
115
- }
116
- else
117
- {
118
- channelObject.resetControllers();
119
- }
120
- break;
121
-
122
- case workletMessageType.setChannelVibrato:
123
- if (channel === ALL_CHANNELS_OR_DIFFERENT_ACTION)
124
- {
125
- for (let i = 0; i < this.synthesizer.midiAudioChannels.length; i++)
126
- {
127
- const chan = this.synthesizer.midiAudioChannels[i];
128
- if (data.rate === ALL_CHANNELS_OR_DIFFERENT_ACTION)
129
- {
130
- chan.disableAndLockGSNRPN();
131
- }
132
- else
133
- {
134
- chan.setVibrato(data.depth, data.rate, data.delay);
135
- }
136
- }
137
- }
138
- else if (data.rate === ALL_CHANNELS_OR_DIFFERENT_ACTION)
139
- {
140
- channelObject.disableAndLockGSNRPN();
141
- }
142
- else
143
- {
144
- channelObject.setVibrato(data.depth, data.rate, data.delay);
145
- }
146
- break;
147
-
148
- case workletMessageType.stopAll:
149
- if (channel === ALL_CHANNELS_OR_DIFFERENT_ACTION)
150
- {
151
- this.synthesizer.stopAllChannels(data === 1);
152
- }
153
- else
154
- {
155
- channelObject.stopAllNotes(data === 1);
156
- }
157
- break;
158
-
159
- case workletMessageType.killNotes:
160
- this.synthesizer.voiceKilling(data);
161
- break;
162
-
163
- case workletMessageType.muteChannel:
164
- channelObject.muteChannel(data);
165
- break;
166
-
167
- case workletMessageType.addNewChannel:
168
- this.synthesizer.createWorkletChannel(true);
169
- break;
170
-
171
- case workletMessageType.debugMessage:
172
- this.synthesizer.debugMessage();
173
- break;
174
-
175
- case workletMessageType.setMasterParameter:
176
- /**
177
- * @type {masterParameterType}
178
- */
179
- const type = data[0];
180
- const value = data[1];
181
- this.synthesizer.setMasterParameter(type, value);
182
- break;
183
-
184
- case workletMessageType.setDrums:
185
- channelObject.setDrums(data);
186
- break;
187
-
188
- case workletMessageType.transpose:
189
- if (channel === ALL_CHANNELS_OR_DIFFERENT_ACTION)
190
- {
191
- this.synthesizer.transposeAllChannels(data[0], data[1]);
192
- }
193
- else
194
- {
195
- channelObject.transposeChannel(data[0], data[1]);
196
- }
197
- break;
198
-
199
- case workletMessageType.highPerformanceMode:
200
- this.synthesizer.highPerformanceMode = data;
201
- break;
202
-
203
- case workletMessageType.lockController:
204
- if (data[0] === ALL_CHANNELS_OR_DIFFERENT_ACTION)
205
- {
206
- channelObject.setPresetLock(data[1]);
207
- }
208
- else
209
- {
210
- channelObject.lockedControllers[data[0]] = data[1];
211
- }
212
- break;
213
-
214
- case workletMessageType.sequencerSpecific:
215
- this.synthesizer.sequencer.processMessage(data.messageType, data.messageData);
216
- break;
217
-
218
- case workletMessageType.soundFontManager:
219
- try
220
- {
221
- this.synthesizer.soundfontManager.handleMessage(data[0], data[1]);
222
- }
223
- catch (e)
224
- {
225
- this.postMessageToMainThread({
226
- messageType: returnMessageType.soundfontError,
227
- messageData: e
228
- });
229
- }
230
- this.synthesizer.clearSoundFont(true, false);
231
- break;
232
-
233
- case workletMessageType.keyModifierManager:
234
- /**
235
- * @type {workletKeyModifierMessageType}
236
- */
237
- const keyMessageType = data[0];
238
- const man = this.synthesizer.keyModifierManager;
239
- const keyMessageData = data[1];
240
- switch (keyMessageType)
241
- {
242
- default:
243
- return;
244
-
245
- case workletKeyModifierMessageType.addMapping:
246
- man.addMapping(...keyMessageData);
247
- break;
248
-
249
- case workletKeyModifierMessageType.clearMappings:
250
- man.clearMappings();
251
- break;
252
-
253
- case workletKeyModifierMessageType.deleteMapping:
254
- man.deleteMapping(...keyMessageData);
255
- }
256
- break;
257
-
258
- case workletMessageType.requestSynthesizerSnapshot:
259
- const snapshot = SynthesizerSnapshot.createSynthesizerSnapshot(this.synthesizer);
260
- this.postMessageToMainThread({
261
- messageType: returnMessageType.synthesizerSnapshot,
262
- messageData: snapshot
263
- });
264
- break;
265
-
266
- case workletMessageType.setLogLevel:
267
- SpessaSynthLogging(data[0], data[1], data[2], data[3]);
268
- break;
269
-
270
- case workletMessageType.setEffectsGain:
271
- this.synthesizer.reverbGain = data[0];
272
- this.synthesizer.chorusGain = data[1];
273
- break;
274
-
275
- case workletMessageType.destroyWorklet:
276
- this.alive = false;
277
- this.synthesizer.destroySynthProcessor();
278
- break;
279
-
280
- default:
281
- SpessaSynthWarn("Unrecognized event:", data);
282
- break;
283
- }
284
- }
285
-
286
- // noinspection JSUnusedGlobalSymbols
287
- /**
288
- * the audio worklet processing logic
289
- * @param inputs {Float32Array[][]} required by WebAudioAPI
290
- * @param outputs {Float32Array[][]} the outputs to write to, only the first two channels are populated
291
- * @returns {boolean} true unless it's not alive
292
- */
293
- process(inputs, outputs)
294
- {
295
- if (!this.alive)
296
- {
297
- return false;
298
- }
299
- if (this.oneOutputMode)
300
- {
301
- const out = outputs[0];
302
- // 1 output with 32 channels.
303
- // channels are ordered as follows:
304
- // midiChannel1L, midiChannel1R,
305
- // midiChannel2L, midiChannel2R
306
- // and so on
307
- /**
308
- * @type {Float32Array[][]}
309
- */
310
- const channelMap = [];
311
- for (let i = 0; i < 32; i += 2)
312
- {
313
- channelMap.push([out[i], out[i + 1]]);
314
- }
315
- this.synthesizer.renderAudioSplit(
316
- [], [], // effects are disabled
317
- channelMap
318
- );
319
- }
320
- else
321
- {
322
- // 18 outputs, each a stereo one
323
- // 0: reverb
324
- // 1: chorus
325
- // 2: channel 1
326
- // 3: channel 2
327
- // and so on
328
- this.synthesizer.renderAudioSplit(
329
- outputs[0], // reverb
330
- outputs[1], // chorus
331
- outputs.slice(2)
332
- );
333
- }
334
- return true;
335
- }
336
- }
337
-
338
- // noinspection JSUnresolvedReference
339
- registerProcessor(WORKLET_PROCESSOR_NAME, WorkletSpessaProcessor);
340
- SpessaSynthInfo("%cProcessor succesfully registered!", consoleColors.recognized);
@@ -1,16 +0,0 @@
1
- /**
2
- * The absolute path (from the spessasynth_lib folder) to the worklet module
3
- * @type {string}
4
- */
5
- export const WORKLET_URL_ABSOLUTE = "synthetizer/worklet_processor.min.js";
6
- /**
7
- * @typedef {Object} StartRenderingDataConfig
8
- * @property {BasicMIDI} parsedMIDI - the MIDI to render
9
- * @property {SynthesizerSnapshot?} snapshot - the snapshot to apply
10
- * @property {boolean?} oneOutput - if synth should use one output with 32 channels (2 audio channels for each midi channel).
11
- * this disabled chorus and reverb.
12
- * @property {number?} loopCount - the times to loop the song
13
- * @property {SequencerOptions?} sequencerOptions - the options to pass to the sequencer
14
- */
15
-
16
- export const WORKLET_PROCESSOR_NAME = "spessasynth-worklet-processor";
package/utils/README.md DELETED
@@ -1,5 +0,0 @@
1
- ## This is the utility folder.
2
-
3
- There are various utilites here used by the SpessaSynth library.
4
-
5
- ### Note that the stbvorbis_sync.js is licensed under Apache-2.0.
@@ -1,186 +0,0 @@
1
- /**
2
- * @typedef {Object} WaveMetadata
3
- * @property {string|undefined} title - the song's title
4
- * @property {string|undefined} artist - the song's artist
5
- * @property {string|undefined} album - the song's album
6
- * @property {string|undefined} genre - the song's genre
7
- */
8
-
9
- import { combineArrays, IndexedByteArray } from "./indexed_array.js";
10
- import { getStringBytes, writeStringAsBytes } from "./byte_functions/string.js";
11
- import { writeRIFFOddSize } from "../soundfont/basic_soundfont/riff_chunk.js";
12
- import { writeLittleEndian } from "./byte_functions/little_endian.js";
13
-
14
- /**
15
- *
16
- * @param audioBuffer {AudioBuffer}
17
- * @param normalizeAudio {boolean} find the max sample point and set it to 1, and scale others with it
18
- * @param channelOffset {number} channel offset and channel offset + 1 get saved
19
- * @param metadata {WaveMetadata}
20
- * @param loop {{start: number, end: number}} loop start and end points in seconds. Undefined if no loop
21
- * @returns {Blob}
22
- */
23
- export function audioBufferToWav(audioBuffer, normalizeAudio = true, channelOffset = 0, metadata = {}, loop = undefined)
24
- {
25
- const channel1Data = audioBuffer.getChannelData(channelOffset);
26
- const channel2Data = audioBuffer.getChannelData(channelOffset + 1);
27
- const length = channel1Data.length;
28
-
29
- const bytesPerSample = 2; // 16-bit PCM
30
-
31
- // prepare INFO chunk
32
- let infoChunk = new IndexedByteArray(0);
33
- const infoOn = Object.keys(metadata).length > 0;
34
- // INFO chunk
35
- if (infoOn)
36
- {
37
- const encoder = new TextEncoder();
38
- const infoChunks = [
39
- getStringBytes("INFO"),
40
- writeRIFFOddSize("ICMT", encoder.encode("Created with SpessaSynth"), true)
41
- ];
42
- if (metadata.artist)
43
- {
44
- infoChunks.push(
45
- writeRIFFOddSize("IART", encoder.encode(metadata.artist), true)
46
- );
47
- }
48
- if (metadata.album)
49
- {
50
- infoChunks.push(
51
- writeRIFFOddSize("IPRD", encoder.encode(metadata.album), true)
52
- );
53
- }
54
- if (metadata.genre)
55
- {
56
- infoChunks.push(
57
- writeRIFFOddSize("IGNR", encoder.encode(metadata.genre), true)
58
- );
59
- }
60
- if (metadata.title)
61
- {
62
- infoChunks.push(
63
- writeRIFFOddSize("INAM", encoder.encode(metadata.title), true)
64
- );
65
- }
66
- infoChunk = writeRIFFOddSize("LIST", combineArrays(infoChunks));
67
- }
68
-
69
- // prepare CUE chunk
70
- let cueChunk = new IndexedByteArray(0);
71
- const cueOn = loop?.end !== undefined && loop?.start !== undefined;
72
- if (cueOn)
73
- {
74
- const loopStartSamples = Math.floor(loop.start * audioBuffer.sampleRate);
75
- const loopEndSamples = Math.floor(loop.end * audioBuffer.sampleRate);
76
-
77
- const cueStart = new IndexedByteArray(24);
78
- writeLittleEndian(cueStart, 0, 4); // dwIdentifier
79
- writeLittleEndian(cueStart, 0, 4); // dwPosition
80
- writeStringAsBytes(cueStart, "data"); // cue point ID
81
- writeLittleEndian(cueStart, 0, 4); // chunkStart, always 0
82
- writeLittleEndian(cueStart, 0, 4); // BlockStart, always 0
83
- writeLittleEndian(cueStart, loopStartSamples, 4); // sampleOffset
84
-
85
- const cueEnd = new IndexedByteArray(24);
86
- writeLittleEndian(cueEnd, 1, 4); // dwIdentifier
87
- writeLittleEndian(cueEnd, 0, 4); // dwPosition
88
- writeStringAsBytes(cueEnd, "data"); // cue point ID
89
- writeLittleEndian(cueEnd, 0, 4); // chunkStart, always 0
90
- writeLittleEndian(cueEnd, 0, 4); // BlockStart, always 0
91
- writeLittleEndian(cueEnd, loopEndSamples, 4); // sampleOffset
92
-
93
- const out = combineArrays([
94
- new IndexedByteArray([2, 0, 0, 0]), // cue points count,
95
- cueStart,
96
- cueEnd
97
- ]);
98
- cueChunk = writeRIFFOddSize("cue ", out);
99
- }
100
-
101
- // Prepare the header
102
- const headerSize = 44;
103
- const dataSize = length * 2 * bytesPerSample; // 2 channels, 16-bit per channel
104
- const fileSize = headerSize + dataSize + infoChunk.length + cueChunk.length - 8; // total file size minus the first 8 bytes
105
- const header = new Uint8Array(headerSize);
106
-
107
- // 'RIFF'
108
- header.set([82, 73, 70, 70], 0);
109
- // file length
110
- header.set(
111
- new Uint8Array([fileSize & 0xff, (fileSize >> 8) & 0xff, (fileSize >> 16) & 0xff, (fileSize >> 24) & 0xff]),
112
- 4
113
- );
114
- // 'WAVE'
115
- header.set([87, 65, 86, 69], 8);
116
- // 'fmt '
117
- header.set([102, 109, 116, 32], 12);
118
- // fmt chunk length
119
- header.set([16, 0, 0, 0], 16); // 16 for PCM
120
- // audio format (PCM)
121
- header.set([1, 0], 20);
122
- // number of channels (2)
123
- header.set([2, 0], 22);
124
- // sample rate
125
- const sampleRate = audioBuffer.sampleRate;
126
- header.set(
127
- new Uint8Array([sampleRate & 0xff, (sampleRate >> 8) & 0xff, (sampleRate >> 16) & 0xff, (sampleRate >> 24) & 0xff]),
128
- 24
129
- );
130
- // byte rate (sample rate * block align)
131
- const byteRate = sampleRate * 2 * bytesPerSample; // 2 channels, 16-bit per channel
132
- header.set(
133
- new Uint8Array([byteRate & 0xff, (byteRate >> 8) & 0xff, (byteRate >> 16) & 0xff, (byteRate >> 24) & 0xff]),
134
- 28
135
- );
136
- // block align (channels * bytes per sample)
137
- header.set([4, 0], 32); // 2 channels * 16-bit per channel / 8
138
- // bits per sample
139
- header.set([16, 0], 34); // 16-bit
140
-
141
- // data chunk identifier 'data'
142
- header.set([100, 97, 116, 97], 36);
143
- // data chunk length
144
- header.set(
145
- new Uint8Array([dataSize & 0xff, (dataSize >> 8) & 0xff, (dataSize >> 16) & 0xff, (dataSize >> 24) & 0xff]),
146
- 40
147
- );
148
-
149
- let wavData = new Uint8Array(fileSize + 8);
150
- let offset = headerSize;
151
- wavData.set(header, 0);
152
-
153
- // Interleave audio data (combine channels)
154
- let multiplier = 32767;
155
- if (normalizeAudio)
156
- {
157
- // find min and max values to prevent clipping when converting to 16 bits
158
- const maxAbsValue = channel1Data.map((v, i) => Math.max(Math.abs(v), Math.abs(channel2Data[i])))
159
- .reduce((a, b) => Math.max(a, b));
160
- multiplier = maxAbsValue > 0 ? (32767 / maxAbsValue) : 1;
161
- }
162
- for (let i = 0; i < length; i++)
163
- {
164
- // interleave both channels
165
- const sample1 = Math.min(32767, Math.max(-32768, channel1Data[i] * multiplier));
166
- const sample2 = Math.min(32767, Math.max(-32768, channel2Data[i] * multiplier));
167
-
168
- // convert to 16-bit
169
- wavData[offset++] = sample1 & 0xff;
170
- wavData[offset++] = (sample1 >> 8) & 0xff;
171
- wavData[offset++] = sample2 & 0xff;
172
- wavData[offset++] = (sample2 >> 8) & 0xff;
173
- }
174
-
175
- if (infoOn)
176
- {
177
- wavData.set(infoChunk, offset);
178
- offset += infoChunk.length;
179
- }
180
- if (cueOn)
181
- {
182
- wavData.set(cueChunk, offset);
183
- }
184
-
185
- return new Blob([wavData.buffer], { type: "audio/wav" });
186
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Reads as Big endian
3
- * @param dataArray {IndexedByteArray}
4
- * @param bytesAmount {number}
5
- * @returns {number}
6
- */
7
- export function readBytesAsUintBigEndian(dataArray, bytesAmount)
8
- {
9
- let out = 0;
10
- for (let i = 8 * (bytesAmount - 1); i >= 0; i -= 8)
11
- {
12
- out |= (dataArray[dataArray.currentIndex++] << i);
13
- }
14
- return out >>> 0;
15
- }
16
-
17
- /**
18
- * @param number {number}
19
- * @param bytesAmount {number}
20
- * @returns {number[]}
21
- */
22
- export function writeBytesAsUintBigEndian(number, bytesAmount)
23
- {
24
- const bytes = new Array(bytesAmount).fill(0);
25
- for (let i = bytesAmount - 1; i >= 0; i--)
26
- {
27
- bytes[i] = number & 0xFF;
28
- number >>= 8;
29
- }
30
-
31
- return bytes;
32
- }
@@ -1,77 +0,0 @@
1
- /**
2
- * Reads as little endian
3
- * @param dataArray {IndexedByteArray}
4
- * @param bytesAmount {number}
5
- * @returns {number}
6
- */
7
- export function readLittleEndian(dataArray, bytesAmount)
8
- {
9
- let out = 0;
10
- for (let i = 0; i < bytesAmount; i++)
11
- {
12
- out |= (dataArray[dataArray.currentIndex++] << i * 8);
13
- }
14
- // make sure it stays unsigned
15
- return out >>> 0;
16
- }
17
-
18
- /**
19
- * Writes a number as little endian seems to also work for negative numbers so yay?
20
- * @param dataArray {IndexedByteArray}
21
- * @param number {number}
22
- * @param byteTarget {number}
23
- */
24
- export function writeLittleEndian(dataArray, number, byteTarget)
25
- {
26
- for (let i = 0; i < byteTarget; i++)
27
- {
28
- dataArray[dataArray.currentIndex++] = (number >> (i * 8)) & 0xFF;
29
- }
30
- }
31
-
32
- /**
33
- * @param dataArray {IndexedByteArray}
34
- * @param word {number}
35
- */
36
- export function writeWord(dataArray, word)
37
- {
38
- dataArray[dataArray.currentIndex++] = word & 0xFF;
39
- dataArray[dataArray.currentIndex++] = word >> 8;
40
- }
41
-
42
- /**
43
- * @param dataArray {IndexedByteArray}
44
- * @param dword {number}
45
- */
46
- export function writeDword(dataArray, dword)
47
- {
48
- writeLittleEndian(dataArray, dword, 4);
49
- }
50
-
51
- /**
52
- * @param byte1 {number}
53
- * @param byte2 {number}
54
- * @returns {number}
55
- */
56
- export function signedInt16(byte1, byte2)
57
- {
58
- let val = (byte2 << 8) | byte1;
59
- if (val > 32767)
60
- {
61
- return val - 65536;
62
- }
63
- return val;
64
- }
65
-
66
- /**
67
- * @param byte {number}
68
- * @returns {number}
69
- */
70
- export function signedInt8(byte)
71
- {
72
- if (byte > 127)
73
- {
74
- return byte - 256;
75
- }
76
- return byte;
77
- }