spessasynth_lib 3.25.23 → 3.26.1

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 (162) hide show
  1. package/README.md +29 -114
  2. package/external_midi/midi_handler.js +14 -14
  3. package/external_midi/web_midi_link.js +3 -3
  4. package/index.js +33 -33
  5. package/package.json +19 -6
  6. package/{midi → sequencer}/midi_data.js +1 -1
  7. package/sequencer/{worklet_wrapper/sequencer.js → sequencer.js} +13 -12
  8. package/sequencer/{worklet_wrapper/sequencer_message.js → sequencer_message.js} +1 -1
  9. package/synthetizer/README.md +29 -1
  10. package/synthetizer/audio_effects/reverb_as_binary.js +2 -2
  11. package/synthetizer/{worklet_wrapper/key_modifier_manager.js → key_modifier_manager.js} +11 -2
  12. package/synthetizer/{worklet_wrapper/synth_event_handler.js → synth_event_handler.js} +16 -13
  13. package/synthetizer/{worklet_wrapper/synth_soundfont_manager.js → synth_soundfont_manager.js} +8 -5
  14. package/synthetizer/{worklet_wrapper/synthetizer.js → synthetizer.js} +29 -23
  15. package/synthetizer/{audio_engine/message_protocol/worklet_message.js → worklet_message.js} +15 -2
  16. package/synthetizer/{worklet_wrapper/worklet_processor.js → worklet_processor.js} +214 -31
  17. package/synthetizer/worklet_processor.min.js +13 -12
  18. package/synthetizer/worklet_processor.min.js.map +7 -0
  19. package/synthetizer/{worklet_wrapper/worklet_url.js → worklet_url.js} +2 -0
  20. package/utils/buffer_to_wav.js +7 -165
  21. package/utils/other.js +3 -84
  22. package/externals/fflate/LICENSE +0 -21
  23. package/externals/fflate/fflate.min.js +0 -1
  24. package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  25. package/externals/stbvorbis_sync/LICENSE +0 -202
  26. package/externals/stbvorbis_sync/NOTICE +0 -6
  27. package/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  28. package/midi/README.md +0 -32
  29. package/midi/basic_midi.js +0 -565
  30. package/midi/midi_builder.js +0 -202
  31. package/midi/midi_loader.js +0 -324
  32. package/midi/midi_message.js +0 -254
  33. package/midi/midi_sequence.js +0 -225
  34. package/midi/midi_tools/get_note_times.js +0 -154
  35. package/midi/midi_tools/midi_editor.js +0 -611
  36. package/midi/midi_tools/midi_writer.js +0 -99
  37. package/midi/midi_tools/rmidi_writer.js +0 -567
  38. package/midi/midi_tools/used_keys_loaded.js +0 -238
  39. package/midi/xmf_loader.js +0 -454
  40. package/sequencer/sequencer_engine/events.js +0 -104
  41. package/sequencer/sequencer_engine/play.js +0 -353
  42. package/sequencer/sequencer_engine/process_event.js +0 -169
  43. package/sequencer/sequencer_engine/process_tick.js +0 -106
  44. package/sequencer/sequencer_engine/sequencer_engine.js +0 -335
  45. package/sequencer/sequencer_engine/song_control.js +0 -229
  46. package/soundfont/README.md +0 -13
  47. package/soundfont/basic_soundfont/basic_instrument.js +0 -77
  48. package/soundfont/basic_soundfont/basic_preset.js +0 -336
  49. package/soundfont/basic_soundfont/basic_sample.js +0 -197
  50. package/soundfont/basic_soundfont/basic_soundfont.js +0 -565
  51. package/soundfont/basic_soundfont/basic_zone.js +0 -64
  52. package/soundfont/basic_soundfont/basic_zones.js +0 -43
  53. package/soundfont/basic_soundfont/generator.js +0 -220
  54. package/soundfont/basic_soundfont/modulator.js +0 -378
  55. package/soundfont/basic_soundfont/riff_chunk.js +0 -149
  56. package/soundfont/basic_soundfont/write_dls/art2.js +0 -173
  57. package/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  58. package/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -400
  59. package/soundfont/basic_soundfont/write_dls/ins.js +0 -103
  60. package/soundfont/basic_soundfont/write_dls/lins.js +0 -18
  61. package/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  62. package/soundfont/basic_soundfont/write_dls/rgn2.js +0 -121
  63. package/soundfont/basic_soundfont/write_dls/wave.js +0 -94
  64. package/soundfont/basic_soundfont/write_dls/write_dls.js +0 -119
  65. package/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  66. package/soundfont/basic_soundfont/write_dls/wvpl.js +0 -32
  67. package/soundfont/basic_soundfont/write_sf2/ibag.js +0 -39
  68. package/soundfont/basic_soundfont/write_sf2/igen.js +0 -80
  69. package/soundfont/basic_soundfont/write_sf2/imod.js +0 -46
  70. package/soundfont/basic_soundfont/write_sf2/inst.js +0 -34
  71. package/soundfont/basic_soundfont/write_sf2/pbag.js +0 -39
  72. package/soundfont/basic_soundfont/write_sf2/pgen.js +0 -82
  73. package/soundfont/basic_soundfont/write_sf2/phdr.js +0 -42
  74. package/soundfont/basic_soundfont/write_sf2/pmod.js +0 -46
  75. package/soundfont/basic_soundfont/write_sf2/sdta.js +0 -80
  76. package/soundfont/basic_soundfont/write_sf2/shdr.js +0 -55
  77. package/soundfont/basic_soundfont/write_sf2/write.js +0 -222
  78. package/soundfont/dls/articulator_converter.js +0 -396
  79. package/soundfont/dls/dls_destinations.js +0 -38
  80. package/soundfont/dls/dls_preset.js +0 -44
  81. package/soundfont/dls/dls_sample.js +0 -75
  82. package/soundfont/dls/dls_soundfont.js +0 -186
  83. package/soundfont/dls/dls_sources.js +0 -62
  84. package/soundfont/dls/dls_zone.js +0 -95
  85. package/soundfont/dls/read_articulation.js +0 -299
  86. package/soundfont/dls/read_instrument.js +0 -121
  87. package/soundfont/dls/read_instrument_list.js +0 -17
  88. package/soundfont/dls/read_lart.js +0 -35
  89. package/soundfont/dls/read_region.js +0 -152
  90. package/soundfont/dls/read_samples.js +0 -270
  91. package/soundfont/load_soundfont.js +0 -21
  92. package/soundfont/read_sf2/generators.js +0 -46
  93. package/soundfont/read_sf2/instruments.js +0 -66
  94. package/soundfont/read_sf2/modulators.js +0 -36
  95. package/soundfont/read_sf2/presets.js +0 -80
  96. package/soundfont/read_sf2/samples.js +0 -304
  97. package/soundfont/read_sf2/soundfont.js +0 -305
  98. package/soundfont/read_sf2/zones.js +0 -263
  99. package/synthetizer/audio_engine/README.md +0 -25
  100. package/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -266
  101. package/synthetizer/audio_engine/engine_components/controller_tables.js +0 -88
  102. package/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -149
  103. package/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  104. package/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  105. package/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -471
  106. package/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  107. package/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  108. package/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -228
  109. package/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -120
  110. package/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  111. package/synthetizer/audio_engine/engine_components/voice.js +0 -519
  112. package/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -401
  113. package/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -263
  114. package/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -132
  115. package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
  116. package/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -241
  117. package/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -27
  118. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -253
  119. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -66
  120. package/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  121. package/synthetizer/audio_engine/engine_methods/note_on.js +0 -175
  122. package/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  123. package/synthetizer/audio_engine/engine_methods/program_change.js +0 -61
  124. package/synthetizer/audio_engine/engine_methods/render_voice.js +0 -196
  125. package/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -30
  126. package/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
  127. package/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +0 -40
  128. package/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +0 -34
  129. package/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -21
  130. package/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -20
  131. package/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -55
  132. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  133. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  134. package/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  135. package/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -776
  136. package/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -24
  137. package/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -33
  138. package/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -31
  139. package/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  140. package/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -27
  141. package/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  142. package/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  143. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  144. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  145. package/synthetizer/audio_engine/main_processor.js +0 -765
  146. package/synthetizer/audio_engine/message_protocol/README.md +0 -13
  147. package/synthetizer/audio_engine/message_protocol/message_sending.js +0 -22
  148. package/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -14
  149. package/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  150. package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -122
  151. package/synthetizer/synth_constants.js +0 -20
  152. package/utils/README.md +0 -5
  153. package/utils/byte_functions/big_endian.js +0 -32
  154. package/utils/byte_functions/little_endian.js +0 -77
  155. package/utils/byte_functions/string.js +0 -107
  156. package/utils/byte_functions/variable_length_quantity.js +0 -42
  157. package/utils/indexed_array.js +0 -52
  158. package/utils/loggin.js +0 -79
  159. package/utils/sysex_detector.js +0 -58
  160. package/utils/xg_hacks.js +0 -193
  161. /package/sequencer/{worklet_wrapper/default_sequencer_options.js → default_sequencer_options.js} +0 -0
  162. /package/synthetizer/{worklet_wrapper/sfman_message.js → sfman_message.js} +0 -0
@@ -1,263 +0,0 @@
1
- import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
2
- import { IndexedByteArray } from "../../utils/indexed_array.js";
3
- import { RiffChunk } from "../basic_soundfont/riff_chunk.js";
4
- import { BasicInstrumentZone, BasicPresetZone } from "../basic_soundfont/basic_zones.js";
5
- import { Generator, generatorTypes } from "../basic_soundfont/generator.js";
6
- import { Modulator } from "../basic_soundfont/modulator.js";
7
-
8
- /**
9
- * zones.js
10
- * purpose: reads instrumend and preset zones from soundfont and gets their respective samples and generators and modulators
11
- */
12
-
13
- export class InstrumentZone extends BasicInstrumentZone
14
- {
15
- /**
16
- * Creates a zone (instrument)
17
- * @param dataArray {IndexedByteArray}
18
- */
19
- constructor(dataArray)
20
- {
21
- super();
22
- this.generatorZoneStartIndex = readLittleEndian(dataArray, 2);
23
- this.modulatorZoneStartIndex = readLittleEndian(dataArray, 2);
24
- this.modulatorZoneSize = 0;
25
- this.generatorZoneSize = 0;
26
- this.isGlobal = true;
27
- }
28
-
29
- setZoneSize(modulatorZoneSize, generatorZoneSize)
30
- {
31
- this.modulatorZoneSize = modulatorZoneSize;
32
- this.generatorZoneSize = generatorZoneSize;
33
- }
34
-
35
- /**
36
- * grab the generators
37
- * @param generators {Generator[]}
38
- */
39
- getGenerators(generators)
40
- {
41
- for (let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
42
- {
43
- this.generators.push(generators[i]);
44
- }
45
- }
46
-
47
- /**
48
- * grab the modulators
49
- * @param modulators {Modulator[]}
50
- */
51
- getModulators(modulators)
52
- {
53
- for (let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
54
- {
55
- this.modulators.push(modulators[i]);
56
- }
57
- }
58
-
59
- /**
60
- * Loads the zone's sample
61
- * @param samples {BasicSample[]}
62
- */
63
- getSample(samples)
64
- {
65
- let sampleID = this.generators.find(g => g.generatorType === generatorTypes.sampleID);
66
- if (sampleID)
67
- {
68
- this.sample = samples[sampleID.generatorValue];
69
- this.isGlobal = false;
70
- this.sample.useCount++;
71
- }
72
- }
73
-
74
- /**
75
- * Reads the keyRange of the zone
76
- */
77
- getKeyRange()
78
- {
79
- let range = this.generators.find(g => g.generatorType === generatorTypes.keyRange);
80
- if (range)
81
- {
82
- this.keyRange.min = range.generatorValue & 0x7F;
83
- this.keyRange.max = (range.generatorValue >> 8) & 0x7F;
84
- }
85
- }
86
-
87
- /**
88
- * reads the velolicty range of the zone
89
- */
90
- getVelRange()
91
- {
92
- let range = this.generators.find(g => g.generatorType === generatorTypes.velRange);
93
- if (range)
94
- {
95
- this.velRange.min = range.generatorValue & 0x7F;
96
- this.velRange.max = (range.generatorValue >> 8) & 0x7F;
97
- }
98
- }
99
- }
100
-
101
- /**
102
- * Reads the given instrument zone read
103
- * @param zonesChunk {RiffChunk}
104
- * @param instrumentGenerators {Generator[]}
105
- * @param instrumentModulators {Modulator[]}
106
- * @param instrumentSamples {BasicSample[]}
107
- * @returns {InstrumentZone[]}
108
- */
109
- export function readInstrumentZones(zonesChunk, instrumentGenerators, instrumentModulators, instrumentSamples)
110
- {
111
- /**
112
- * @type {InstrumentZone[]}
113
- */
114
- let zones = [];
115
- while (zonesChunk.chunkData.length > zonesChunk.chunkData.currentIndex)
116
- {
117
- let zone = new InstrumentZone(zonesChunk.chunkData);
118
- if (zones.length > 0)
119
- {
120
- let modulatorZoneSize = zone.modulatorZoneStartIndex - zones[zones.length - 1].modulatorZoneStartIndex;
121
- let generatorZoneSize = zone.generatorZoneStartIndex - zones[zones.length - 1].generatorZoneStartIndex;
122
- zones[zones.length - 1].setZoneSize(modulatorZoneSize, generatorZoneSize);
123
- zones[zones.length - 1].getGenerators(instrumentGenerators);
124
- zones[zones.length - 1].getModulators(instrumentModulators);
125
- zones[zones.length - 1].getSample(instrumentSamples);
126
- zones[zones.length - 1].getKeyRange();
127
- zones[zones.length - 1].getVelRange();
128
- }
129
- zones.push(zone);
130
- }
131
- if (zones.length > 1)
132
- {
133
- // remove terminal
134
- zones.pop();
135
- }
136
- return zones;
137
- }
138
-
139
- export class PresetZone extends BasicPresetZone
140
- {
141
- /**
142
- * Creates a zone (preset)
143
- * @param dataArray {IndexedByteArray}
144
- */
145
- constructor(dataArray)
146
- {
147
- super();
148
- this.generatorZoneStartIndex = readLittleEndian(dataArray, 2);
149
- this.modulatorZoneStartIndex = readLittleEndian(dataArray, 2);
150
- this.modulatorZoneSize = 0;
151
- this.generatorZoneSize = 0;
152
- this.isGlobal = true;
153
- }
154
-
155
- setZoneSize(modulatorZoneSize, generatorZoneSize)
156
- {
157
- this.modulatorZoneSize = modulatorZoneSize;
158
- this.generatorZoneSize = generatorZoneSize;
159
- }
160
-
161
- /**
162
- * grab the generators
163
- * @param generators {Generator[]}
164
- */
165
- getGenerators(generators)
166
- {
167
- for (let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
168
- {
169
- this.generators.push(generators[i]);
170
- }
171
- }
172
-
173
- /**
174
- * grab the modulators
175
- * @param modulators {Modulator[]}
176
- */
177
- getModulators(modulators)
178
- {
179
- for (let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
180
- {
181
- this.modulators.push(modulators[i]);
182
- }
183
- }
184
-
185
- /**
186
- * grab the instrument
187
- * @param instruments {BasicInstrument[]}
188
- */
189
- getInstrument(instruments)
190
- {
191
- let instrumentID = this.generators.find(g => g.generatorType === generatorTypes.instrument);
192
- if (instrumentID)
193
- {
194
- this.instrument = instruments[instrumentID.generatorValue];
195
- this.instrument.addUseCount();
196
- this.isGlobal = false;
197
- }
198
- }
199
-
200
- /**
201
- * Reads the keyRange of the zone
202
- */
203
- getKeyRange()
204
- {
205
- let range = this.generators.find(g => g.generatorType === generatorTypes.keyRange);
206
- if (range)
207
- {
208
- this.keyRange.min = range.generatorValue & 0x7F;
209
- this.keyRange.max = (range.generatorValue >> 8) & 0x7F;
210
- }
211
- }
212
-
213
- /**
214
- * reads the velolicty range of the zone
215
- */
216
- getVelRange()
217
- {
218
- let range = this.generators.find(g => g.generatorType === generatorTypes.velRange);
219
- if (range)
220
- {
221
- this.velRange.min = range.generatorValue & 0x7F;
222
- this.velRange.max = (range.generatorValue >> 8) & 0x7F;
223
- }
224
- }
225
- }
226
-
227
- /**
228
- * Reads the given preset zone read
229
- * @param zonesChunk {RiffChunk}
230
- * @param presetGenerators {Generator[]}
231
- * @param instruments {BasicInstrument[]}
232
- * @param presetModulators {Modulator[]}
233
- * @returns {PresetZone[]}
234
- */
235
- export function readPresetZones(zonesChunk, presetGenerators, presetModulators, instruments)
236
- {
237
- /**
238
- * @type {PresetZone[]}
239
- */
240
- let zones = [];
241
- while (zonesChunk.chunkData.length > zonesChunk.chunkData.currentIndex)
242
- {
243
- let zone = new PresetZone(zonesChunk.chunkData);
244
- if (zones.length > 0)
245
- {
246
- let modulatorZoneSize = zone.modulatorZoneStartIndex - zones[zones.length - 1].modulatorZoneStartIndex;
247
- let generatorZoneSize = zone.generatorZoneStartIndex - zones[zones.length - 1].generatorZoneStartIndex;
248
- zones[zones.length - 1].setZoneSize(modulatorZoneSize, generatorZoneSize);
249
- zones[zones.length - 1].getGenerators(presetGenerators);
250
- zones[zones.length - 1].getModulators(presetModulators);
251
- zones[zones.length - 1].getInstrument(instruments);
252
- zones[zones.length - 1].getKeyRange();
253
- zones[zones.length - 1].getVelRange();
254
- }
255
- zones.push(zone);
256
- }
257
- if (zones.length > 1)
258
- {
259
- // remove terminal
260
- zones.pop();
261
- }
262
- return zones;
263
- }
@@ -1,25 +0,0 @@
1
- ## This is the synthesis engine folder.
2
-
3
- The code here is responsible for a single midi channel, synthesizing the sound to it.
4
-
5
- - `engine_methods` contains the methods for the `main_processor.js`
6
- - `engine_components` contains the various digital signal processing functions such as the wavetable oscillator, low
7
- pass filter, etc.
8
-
9
- For those interested, `render_voice.js` file contains the actual DSP synthesis code.
10
-
11
- `minify_processor.js` uses esbuild to minify the processor code. Importing this instead of `worklet_processor.js` is
12
- recommended.
13
-
14
- ## How it works in spessasynth_lib
15
- Both `Synthetizer` and `Sequencer` are essentially "remote control"
16
- for the actual sequencer and synthesizer in the audio worklet thread (here)
17
- These core components are wrapped in the AudioWorkletProcessor, which is receiving both commands and data (MIDIs, sound banks)
18
- through the message port, and sends data back (events, time changes, status changes, etc.).
19
-
20
- For example,
21
- the playback to WebMIDIAPI is actually the sequencer in the worklet thread
22
- playing back the sequence and then postMessaging the commands through the synthesizer to the sequencer
23
- which actually sends them to the specified output.
24
-
25
- The wonders of separate audio thread...
@@ -1,266 +0,0 @@
1
- import { getModulatorCurveValue, MOD_PRECOMPUTED_LENGTH } from "./modulator_curves.js";
2
- import { VolumeEnvelope } from "./volume_envelope.js";
3
- import { ModulationEnvelope } from "./modulation_envelope.js";
4
- import { generatorLimits, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
5
- import { Modulator, modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
6
- import { NON_CC_INDEX_OFFSET } from "./controller_tables.js";
7
-
8
- /**
9
- * compute_modulator.js
10
- * purpose: precomputes all curve types and computes modulators
11
- */
12
-
13
- const EFFECT_MODULATOR_TRANSFORM_MULTIPLIER = 1000 / 200;
14
-
15
- /**
16
- * Computes a given modulator
17
- * @param controllerTable {Int16Array} all midi controllers as 14bit values + the non-controller indexes, starting at 128
18
- * @param modulator {Modulator} the modulator to compute
19
- * @param voice {Voice} the voice belonging to the modulator
20
- * @returns {number} the computed value
21
- */
22
- export function computeModulator(controllerTable, modulator, voice)
23
- {
24
- if (modulator.transformAmount === 0)
25
- {
26
- modulator.currentValue = 0;
27
- return 0;
28
- }
29
- // mapped to 0-16384
30
- let rawSourceValue;
31
- if (modulator.sourceUsesCC)
32
- {
33
- rawSourceValue = controllerTable[modulator.sourceIndex];
34
- }
35
- else
36
- {
37
- const index = modulator.sourceIndex + NON_CC_INDEX_OFFSET;
38
- switch (modulator.sourceIndex)
39
- {
40
- case modulatorSources.noController:
41
- rawSourceValue = 16383; // equals to 1
42
- break;
43
-
44
- case modulatorSources.noteOnKeyNum:
45
- rawSourceValue = voice.midiNote << 7;
46
- break;
47
-
48
- case modulatorSources.noteOnVelocity:
49
- rawSourceValue = voice.velocity << 7;
50
- break;
51
-
52
- case modulatorSources.polyPressure:
53
- rawSourceValue = voice.pressure << 7;
54
- break;
55
-
56
- default:
57
- rawSourceValue = controllerTable[index]; // pitch bend and range are stored in the cc table
58
- break;
59
- }
60
-
61
- }
62
-
63
- const sourceValue = transforms[modulator.sourceCurveType][modulator.sourcePolarity][modulator.sourceDirection][rawSourceValue];
64
-
65
- // mapped to 0-127
66
- let rawSecondSrcValue;
67
- if (modulator.secSrcUsesCC)
68
- {
69
- rawSecondSrcValue = controllerTable[modulator.secSrcIndex];
70
- }
71
- else
72
- {
73
- const index = modulator.secSrcIndex + NON_CC_INDEX_OFFSET;
74
- switch (modulator.secSrcIndex)
75
- {
76
- case modulatorSources.noController:
77
- rawSecondSrcValue = 16383; // equals to 1
78
- break;
79
-
80
- case modulatorSources.noteOnKeyNum:
81
- rawSecondSrcValue = voice.midiNote << 7;
82
- break;
83
-
84
- case modulatorSources.noteOnVelocity:
85
- rawSecondSrcValue = voice.velocity << 7;
86
- break;
87
-
88
- case modulatorSources.polyPressure:
89
- rawSecondSrcValue = voice.pressure << 7;
90
- break;
91
-
92
- default:
93
- rawSecondSrcValue = controllerTable[index]; // pitch bend and range are stored in the cc table
94
- }
95
-
96
- }
97
- const secondSrcValue = transforms[modulator.secSrcCurveType][modulator.secSrcPolarity][modulator.secSrcDirection][rawSecondSrcValue];
98
-
99
- // see the comment for isEffectModulator (modulator.js in basic_soundfont) for explanation
100
- let transformAmount = modulator.transformAmount;
101
- if (modulator.isEffectModulator && transformAmount <= 1000)
102
- {
103
- transformAmount *= EFFECT_MODULATOR_TRANSFORM_MULTIPLIER;
104
- transformAmount = Math.min(transformAmount, 1000);
105
- }
106
-
107
- // compute the modulator
108
- let computedValue = sourceValue * secondSrcValue * transformAmount;
109
-
110
- if (modulator.transformType === 2)
111
- {
112
- // abs value
113
- computedValue = Math.abs(computedValue);
114
- }
115
-
116
- modulator.currentValue = computedValue;
117
- return computedValue;
118
- }
119
-
120
- /**
121
- * Computes modulators of a given voice. Source and index indicate what modulators shall be computed
122
- * @param voice {Voice} the voice to compute modulators for
123
- * @param controllerTable {Int16Array} all midi controllers as 14bit values + the non-controller indexes, starting at 128
124
- * @param sourceUsesCC {number} what modulators should be computed, -1 means all, 0 means modulator source enum 1 means midi controller
125
- * @param sourceIndex {number} enum for the source
126
- */
127
- export function computeModulators(voice, controllerTable, sourceUsesCC = -1, sourceIndex = 0)
128
- {
129
- const modulators = voice.modulators;
130
- const generators = voice.generators;
131
- const modulatedGenerators = voice.modulatedGenerators;
132
-
133
- if (sourceUsesCC === -1)
134
- {
135
- // All modulators mode: compute all modulators
136
- modulatedGenerators.set(generators);
137
- modulators.forEach(mod =>
138
- {
139
- const limits = generatorLimits[mod.modulatorDestination];
140
- const newValue = modulatedGenerators[mod.modulatorDestination] + computeModulator(
141
- controllerTable,
142
- mod,
143
- voice
144
- );
145
- modulatedGenerators[mod.modulatorDestination] = Math.max(
146
- limits.min,
147
- Math.min(newValue, limits.max)
148
- );
149
- });
150
- VolumeEnvelope.recalculate(voice);
151
- ModulationEnvelope.recalculate(voice);
152
- return;
153
- }
154
-
155
- // Optimized mode: calculate only modulators that use the given source
156
- const volenvNeedsRecalculation = new Set([
157
- generatorTypes.initialAttenuation,
158
- generatorTypes.delayVolEnv,
159
- generatorTypes.attackVolEnv,
160
- generatorTypes.holdVolEnv,
161
- generatorTypes.decayVolEnv,
162
- generatorTypes.sustainVolEnv,
163
- generatorTypes.releaseVolEnv,
164
- generatorTypes.keyNumToVolEnvHold,
165
- generatorTypes.keyNumToVolEnvDecay
166
- ]);
167
-
168
- const computedDestinations = new Set();
169
-
170
- modulators.forEach(mod =>
171
- {
172
- if (
173
- (mod.sourceUsesCC === sourceUsesCC && mod.sourceIndex === sourceIndex) ||
174
- (mod.secSrcUsesCC === sourceUsesCC && mod.secSrcIndex === sourceIndex)
175
- )
176
- {
177
- const destination = mod.modulatorDestination;
178
- if (!computedDestinations.has(destination))
179
- {
180
- // Reset this destination
181
- modulatedGenerators[destination] = generators[destination];
182
- // compute our modulator
183
- computeModulator(controllerTable, mod, voice);
184
- // sum the values of all modulators for this destination
185
- modulators.forEach(m =>
186
- {
187
- if (m.modulatorDestination === destination)
188
- {
189
- const limits = generatorLimits[mod.modulatorDestination];
190
- const newValue = modulatedGenerators[mod.modulatorDestination] + m.currentValue;
191
- modulatedGenerators[mod.modulatorDestination] = Math.max(
192
- limits.min,
193
- Math.min(newValue, limits.max)
194
- );
195
- }
196
- });
197
- computedDestinations.add(destination);
198
- }
199
- }
200
- });
201
-
202
- // Recalculate volume envelope if necessary
203
- if ([...computedDestinations].some(dest => volenvNeedsRecalculation.has(dest)))
204
- {
205
- VolumeEnvelope.recalculate(voice);
206
- }
207
-
208
- ModulationEnvelope.recalculate(voice);
209
- }
210
-
211
-
212
- /**
213
- * as follows: transforms[curveType][polarity][direction] is an array
214
- * @type {Float32Array[][][]}
215
- */
216
- const transforms = [];
217
-
218
- for (let curve = 0; curve < 4; curve++)
219
- {
220
- transforms[curve] =
221
- [
222
- [
223
- new Float32Array(MOD_PRECOMPUTED_LENGTH),
224
- new Float32Array(MOD_PRECOMPUTED_LENGTH)
225
- ],
226
- [
227
- new Float32Array(MOD_PRECOMPUTED_LENGTH),
228
- new Float32Array(MOD_PRECOMPUTED_LENGTH)
229
- ]
230
- ];
231
- for (let i = 0; i < MOD_PRECOMPUTED_LENGTH; i++)
232
- {
233
-
234
- // polarity 0 dir 0
235
- transforms[curve][0][0][i] = getModulatorCurveValue(
236
- 0,
237
- curve,
238
- i / MOD_PRECOMPUTED_LENGTH,
239
- 0
240
- );
241
-
242
- // polarity 1 dir 0
243
- transforms[curve][1][0][i] = getModulatorCurveValue(
244
- 0,
245
- curve,
246
- i / MOD_PRECOMPUTED_LENGTH,
247
- 1
248
- );
249
-
250
- // polarity 0 dir 1
251
- transforms[curve][0][1][i] = getModulatorCurveValue(
252
- 1,
253
- curve,
254
- i / MOD_PRECOMPUTED_LENGTH,
255
- 0
256
- );
257
-
258
- // polarity 1 dir 1
259
- transforms[curve][1][1][i] = getModulatorCurveValue(
260
- 1,
261
- curve,
262
- i / MOD_PRECOMPUTED_LENGTH,
263
- 1
264
- );
265
- }
266
- }
@@ -1,88 +0,0 @@
1
- import { midiControllers } from "../../../midi/midi_message.js";
2
- import { modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
3
-
4
- /*
5
- * A bit of explanation:
6
- * The controller table is stored as an int16 array, it stores 14-bit values.
7
- * This controller table is then extended with the modulatorSources section,
8
- * for example, pitch range and pitch range depth.
9
- * This allows us for precise control range and supports full pitch-wheel resolution.
10
- */
11
- export const NON_CC_INDEX_OFFSET = 128;
12
- export const CONTROLLER_TABLE_SIZE = 147;
13
-
14
-
15
- // an array with preset default values, so we can quickly use set() to reset the controllers
16
- export const resetArray = new Int16Array(CONTROLLER_TABLE_SIZE).fill(0);
17
- export const setResetValue = (i, v) => resetArray[i] = v << 7;
18
-
19
- // values come from Falcosoft MidiPlayer 6
20
- setResetValue(midiControllers.mainVolume, 100);
21
- setResetValue(midiControllers.balance, 64);
22
- setResetValue(midiControllers.expressionController, 127);
23
- setResetValue(midiControllers.pan, 64);
24
-
25
- setResetValue(midiControllers.portamentoOnOff, 127);
26
-
27
- setResetValue(midiControllers.filterResonance, 64);
28
- setResetValue(midiControllers.releaseTime, 64);
29
- setResetValue(midiControllers.attackTime, 64);
30
- setResetValue(midiControllers.brightness, 64);
31
-
32
- setResetValue(midiControllers.decayTime, 64);
33
- setResetValue(midiControllers.vibratoRate, 64);
34
- setResetValue(midiControllers.vibratoDepth, 64);
35
- setResetValue(midiControllers.vibratoDelay, 64);
36
- setResetValue(midiControllers.generalPurposeController6, 64);
37
- setResetValue(midiControllers.generalPurposeController8, 64);
38
-
39
- setResetValue(midiControllers.RPNLsb, 127);
40
- setResetValue(midiControllers.RPNMsb, 127);
41
- setResetValue(midiControllers.NRPNLsb, 127);
42
- setResetValue(midiControllers.NRPNMsb, 127);
43
-
44
-
45
- export const PORTAMENTO_CONTROL_UNSET = 1;
46
- // special case: portamento control
47
- // since it is only 7-bit, only the values at multiple of 128 are allowed.
48
- // a value of just 1 indicates no key set, hence no portamento.
49
- // this is the "initial unset portamento key" flag.
50
- resetArray[midiControllers.portamentoControl] = PORTAMENTO_CONTROL_UNSET;
51
-
52
- // pitch wheel
53
- setResetValue(NON_CC_INDEX_OFFSET + modulatorSources.pitchWheel, 64);
54
- setResetValue(NON_CC_INDEX_OFFSET + modulatorSources.pitchWheelRange, 2);
55
-
56
- /**
57
- * @enum {number}
58
- */
59
- export const customControllers = {
60
- channelTuning: 0, // cents, RPN for fine tuning
61
- channelTransposeFine: 1, // cents, only the decimal tuning, (e.g., transpose is 4.5,
62
- // then shift by 4 keys + tune by 50 cents)
63
- modulationMultiplier: 2, // cents, set by modulation depth RPN
64
- masterTuning: 3, // cents, set by system exclusive
65
- channelTuningSemitones: 4 // semitones, for RPN coarse tuning
66
- };
67
- export const CUSTOM_CONTROLLER_TABLE_SIZE = Object.keys(customControllers).length;
68
- export const customResetArray = new Float32Array(CUSTOM_CONTROLLER_TABLE_SIZE);
69
- customResetArray[customControllers.modulationMultiplier] = 1;
70
- /**
71
- * @enum {number}
72
- */
73
- export const dataEntryStates = {
74
- Idle: 0,
75
- RPCoarse: 1,
76
- RPFine: 2,
77
- NRPCoarse: 3,
78
- NRPFine: 4,
79
- DataCoarse: 5,
80
- DataFine: 6
81
- };
82
- /**
83
- * This is a channel configuration enum, it is internally sent from Synthetizer via controller change
84
- * @enum {number}
85
- */
86
- export const channelConfiguration = {
87
- velocityOverride: 128 // overrides velocity for the given channel
88
- };